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私の環状セクターは180度を超えます。

stackoverflow の優れた幾何学的思考を助けてくれてありがとう!

更新 OK、ここで svg キャンバスの相互極性を実行する必要があります。コーヒー スクリプトを使用すると、実際のプロダクション コードが続きます。

 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()はラジアンで動作するため、Math.PIがラジアンとどのように関連しているかをウィキで簡単に読んでから、数式を作成して度(または希望するもの)をラジアンに変換します。
次のようなことをします:(((2 * Math.PI)/ 360)* 270)     (= 3/4円)
ちなみに、ラジアン/単位変換とECMAscriptの浮動小数点で目立った描画の問題は発生しませんでしたポイント動作!

また、beginPath()とclosePath()(および必要に応じてstroke())を忘れないでください。キャンバスに推測させないでください!! これは通常、(閉じた)パスを描画するための鍵です!!

bezierCurveTo()も確認することをお勧めします。

更新(TSの更新について):あなたの写真(私はあなたの問題のレンダリングだと思います)を見ると、私はあなたが望むもの、つまり円グラフの断片を見ると思います。

これは単純で、beginPath()とclosePath()(および塗りつぶし色)の間に2つの円弧と2つの線があります。
やりたいことは、translate()を使用して原点(ポイント0,0)を中央に配置することです。これを行う前に、鮮明な線を取得する方法を確認してください。秘訣は、半分のピクセル(x.5、y.5)に変換することです。

次に、1つの「main-canvas」と1つの「temp-canvas」を作成します。パイごとに、きれいな一時的な帆布を描き(透明な巨大なジャンボの代わりに幅と高さを設定するだけです)、この一時的な帆布をメインの帆布に置きます。最後に、メインキャンバスをレンダリング/出力します。終わり。

スクリプト内の「魔法」(単純な数学)は、既存の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の完全なコードは次のとおりです。円の周りに複数の環状セクションを描画しましたが、1 つだけを描画するように簡単に変更できます。基本的に、内側の半径と外側の半径があり、始点と終点でそれぞれを直線で結びます。

タンジェント座標のタンジェントは私を怒らせています。さらに、私は深刻な懸念を持っています: http://www.dbp-consulting.com/tutorials/canvas/CanvasArcTo.html私の環状セクターは180度を超えます。

arcTo() 関数については正しいです。180 度未満の円弧しか生成できません。>= 180° の接線は交差しないため、arcTo() 関数の制御点はありません。2つまたは(私は環全体に対して3つを行います)互いに隣接して描くことができます.

于 2013-03-30T20:30:41.950 に答える