2011-07-18 19 views

答えて

2

svg ellipseとcanvas arcの違いは、svgに2つの半径があり、arcToに1つしかないことです。次に、キャンバス内の特定の角度で円弧を回転させる必要があります。 2つの半径をエミュレートするには、最小の半径を持つ指定された座標で円弧を作成する必要があります。次に、この円弧を係数(rx/ry)を持つ特定の方向にスケーリングする必要があります。そして今あなたは回転するだけでいいです。しかし、このアプローチでは、楕円のどの部分を表示したいのかは実際には分かりません。なぜなら、それはsvg仕様のlarge-arc-flagとsweep-flagに依存するからです。別の問題は、終了座標(svg specから)でアークを制限することです。だからarcToによって、楕円の最大半分を作ることができると思います。

楕円上に3つのコントロールポイントの座標がある場合、bezierCurveTo(x0、y0、x1、y1、x2、y2)を使用して楕円の一部を描画することもできます。この方法では、楕円の任意のセグメントを作成できます。もちろん、PI以外のセグメントの場合は、少なくとも2つの曲線が必要です

SVG仕様からは、(xx軸回転大円弧スイープフラグxy)があります。だから、サンプルパスはそのようになります:

M100,100 a25,50 -30 0,1 50,-25 

Hereあなたが描画されるべきかベジェ曲線を見つけることがあります。

今、あなたはあなたが-30度まで回転する前にコントロールポイントを計算する必要が (100100です)コンテキストポイントを持っており、(100 + 50,100-25である)エンドポイント

ここで私の作品例:

$(document).ready(function(){ 
     var startX = 100; 
     var startY = 100; 
     var dX = 50; 
     var dY = -25; 
     var angle = -30; 
     var rx = 25; 
     var ry = 50; 
     var svg = Raphael($('#svg')[0], 200, 200); 

     var path = "M" +startX + "," + startY + " a" + rx + "," + ry + " " + angle + " 0,1" + " " + dX + "," +dY; 
     svg.path(path).attr({"stroke-width" : 2, "stroke" : "#FFFFFF"}); 

     var kappa = .5522848, 
     ox = rx*kappa, 
     oy = ry*kappa, 
     xm = startX + rx,  // x-middle 
     ym = startY + ry;  // y-middle 
     var canvas = document.getElementById("canvas"); 
     var ctx = canvas.getContext("2d"); 
     ctx.moveTo(startX,startY); 
     ctx.bezierCurveTo(startX, startY - oy, startX + ox, startY - ry, startX + rx, startY - ry); 
     ctx.bezierCurveTo(startX + rx + ox, startY - ry, startX + 2*rx, startY - oy, startX + dX, startY + dY); 
     ctx.stroke(); 
    }); 

マークアップは単純です:

<div id="svg" style="border: 1px solid black;position : absolute;top : 50px;left : 50px;"></div> 
<canvas id="canvas" width="200px" height="200px" style="border: 1px solid black;position : absolute;top : 300px;left : 50px;"></canvas> 

私は-30度にコントロールポイントを回転させるdidntのため、曲線は類似していません。しかし、私はそれがあなたがする必要がある唯一のものだと信じています。あなたが角度= 0を置く場合、それらは同様です。 回転のための数学を得るためにthis記事を使用することがあります。

PS:私は "M100,100 a25,50 -30 0,1 50を-25" にマップしようとするとキャンバスにthis答え

+0

私のケースへの参照は見つかりませんでした。 – AppleGrew

+0

私は私の答えを編集しました –

+0

ありがとうございました。アプローチ2はより良いです。アプローチ1にスケーリングが必要な場合、これには望ましくない副作用が1つあります。これにより、スケールされたストローク部分が膨張し、曲線が不均一に厚くなります。 – AppleGrew

0

からのコードの一部を取った私の関数を使用します。 私は円弧を念頭に置いてこれを書いた。

ellipse(100,100,50、-25,50、false);

function ellipse(x1, y1, x2, y2, radius, clockwise) { 

var cBx = (x1 + x2)/2; //get point between xy1 and xy2 
var cBy = (y1 + y2)/2; 
var aB = Math.atan2(y1 - y2, x1 - x2); //get angle to bulge point in radians 
if (clockwise) { aB += (90 * (Math.PI/180)); } 
else { aB -= (90 * (Math.PI/180)); } 
var op_side = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2))/2; 
var adj_side = Math.sqrt(Math.pow(radius, 2) - Math.pow(op_side, 2)); 

if (isNaN(adj_side)) { 
    adj_side = Math.sqrt(Math.pow(op_side, 2) - Math.pow(radius, 2)); 
} 

var Cx = cBx + (adj_side * Math.cos(aB));    
var Cy = cBy + (adj_side * Math.sin(aB)); 
var startA = Math.atan2(y1 - Cy, x1 - Cx);  //get start/end angles in radians 
var endA = Math.atan2(y2 - Cy, x2 - Cx); 
var mid = (startA + endA)/2; 
var Mx = Cx + (radius * Math.cos(mid)); 
var My = Cy + (radius * Math.sin(mid)); 
context.arc(Cx, Cy, radius, startA, endA, clockwise); 
} 
0

次のコードセグメントは、私のようにそこにすべてのあなたのためのゲイブ・ラーナーの包括的なCANVGパッケージの関連セクション(https://github.com/canvg/canvgを参照)から抽出し、ゲイブのパッケージの全体の9ヤードを望んでいない可能性があります。以前の解とは異なり、近似ではなく、Gabeに非常に感謝したいSVG円弧要素とまったく同じです。

もう1つのポイントは、パスをプロットする前にキャンバスに既にスケーリングや変換を適用している場合、これをContext.translateへの2回の呼び出しのパラメータに因数分解する必要があることですContext.arcへの呼び出しのradiusパラメータに設定します

function drawSVGarcOnCanvas (Context,lastX,lastY,rx,ry,xAxisRotation,largeArcFlag,sweepFlag,x,y) 
{ 
    //-------------------- 
    // rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y 
    // are the 6 data items in the SVG path declaration following the A 
    // 
    // lastX and lastY are the previous point on the path before the arc 
    //-------------------- 
    // useful functions 
    var m = function ( v) {return Math.sqrt (Math.pow (v[0],2) + Math.pow (v[1],2))}; 
    var r = function (u, v) {return (u[0]*v[0] + u[1]*v[1])/(m(u) * m(v))}; 
    var ang = function (u, v) {return ((u[0]*v[1] < u[1]*v[0])? -1 : 1) * Math.acos (r (u,v))}; 
    //-------------------- 

var currpX = Math.cos (xAxisRotation) * (lastX - x)/2.0 + Math.sin (xAxisRotation) * (lastY - y)/2.0 ; 
var currpY = -Math.sin (xAxisRotation) * (lastX - x)/2.0 + Math.cos (xAxisRotation) * (lastY - y)/2.0 ; 

var l = Math.pow (currpX,2)/Math.pow (rx,2) + Math.pow (currpY,2)/Math.pow (ry,2); 
if (l > 1) {rx *= Math.sqrt (l); ry *= Math.sqrt (l)}; 
var s = ((largeArcFlag == sweepFlag)? -1 : 1) * Math.sqrt 
     (((Math.pow (rx,2) * Math.pow (ry ,2)) - (Math.pow (rx,2) * Math.pow (currpY,2)) - (Math.pow (ry,2) * Math.pow (currpX,2))) 
    /(Math.pow (rx,2) * Math.pow (currpY,2) + Math.pow (ry,2) * Math.pow (currpX,2))); 
if (isNaN (s)) s = 0 ; 

var cppX = s * rx * currpY/ry ; 
var cppY = s * -ry * currpX/rx ; 
var centpX = (lastX + x)/2.0 + Math.cos (xAxisRotation) * cppX - Math.sin (xAxisRotation) * cppY ; 
var centpY = (lastY + y)/2.0 + Math.sin (xAxisRotation) * cppX + Math.cos (xAxisRotation) * cppY ; 

var ang1 = ang ([1,0], [(currpX-cppX)/rx,(currpY-cppY)/ry]); 
var a = [( currpX-cppX)/rx,(currpY-cppY)/ry]; 
var b = [(-currpX-cppX)/rx,(-currpY-cppY)/ry]; 
var angd = ang (a,b); 
if (r (a,b) <= -1) angd = Math.PI; 
if (r (a,b) >= 1) angd = 0; 

var rad = (rx > ry)? rx : ry; 
var sx = (rx > ry)? 1 : rx/ry; 
var sy = (rx > ry)? ry/rx : 1; 

Context.translate (centpX,centpY); 
Context.rotate (xAxisRotation); 
Context.scale (sx, sy); 
Context.arc (0, 0, rad, ang1, ang1 + angd, 1 - sweepFlag); 
Context.scale (1/sx, 1/sy); 
Context.rotate (-xAxisRotation); 
Context.translate (-centpX, -centpY); 
};  
+0

Gabeのコードを投稿する権限がありますか?私。ライセンスはこれを許可していますか? –

関連する問題