楕円のような形を描くネイティブ関数はないようです。また、私は卵の形を探していません。
2つのベジェ曲線で楕円を描くことは可能ですか?誰かがそれを楽しんでいますか?
私の目的は、いくつかの目を引き、実際には円弧を使用することです。前もって感謝します。
ソリューション
したがって、scale()は次のすべての形状のスケーリングを変更します。 Save()は設定を保存してから、復元を使用して設定を復元し、スケーリングせずに新しい形状を描画します。
ジャニのおかげで
ctx.save();
ctx.scale(0.75, 1);
ctx.beginPath();
ctx.arc(20, 21, 10, 0, Math.PI*2, false);
ctx.stroke();
ctx.closePath();
ctx.restore();
更新:
JSBinテストの例 (比較のために他の回答をテストするために更新されました)
オリジナル:
対称の楕円が必要な場合は、常に半径幅の円を作成し、必要な高さに拡大縮小できます(edit:これはストローク幅の外観に影響することに注意してください-acdameliの答え)、ただし、楕円を完全に制御したい場合は、ベジェ曲線を使用する1つの方法があります。
<canvas id="thecanvas" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById('thecanvas');
if(canvas.getContext)
{
var ctx = canvas.getContext('2d');
drawEllipse(ctx, 10, 10, 100, 60);
drawEllipseByCenter(ctx, 60,40,20,10);
}
function drawEllipseByCenter(ctx, cx, cy, w, h) {
drawEllipse(ctx, cx - w/2.0, cy - h/2.0, w, h);
}
function drawEllipse(ctx, x, y, w, h) {
var kappa = .5522848,
ox = (w / 2) * kappa, // control point offset horizontal
oy = (h / 2) * kappa, // control point offset vertical
xe = x + w, // x-end
ye = y + h, // y-end
xm = x + w / 2, // x-middle
ym = y + h / 2; // y-middle
ctx.beginPath();
ctx.moveTo(x, ym);
ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
//ctx.closePath(); // not used correctly, see comments (use to close off open path)
ctx.stroke();
}
</script>
他の場所にあるソリューションの簡易バージョンを以下に示します。正規の円を描き、平行移動して拡大縮小してからストロークします。
function ellipse(context, cx, cy, rx, ry){
context.save(); // save state
context.beginPath();
context.translate(cx-rx, cy-ry);
context.scale(rx, ry);
context.arc(1, 1, 1, 0, 2 * Math.PI, false);
context.restore(); // restore to original state
context.stroke();
}
ベジェ曲線アプローチは、単純な楕円に最適です。さらに制御するには、ループを使用して、x半径とy半径の異なる値(半径、半径?)の楕円を描画できます。
RotationAngleパラメーターを追加すると、楕円を中心を中心に任意の角度で回転できます。部分的な楕円は、ループが実行される範囲(var i)を変更することで描画できます。
この方法で楕円をレンダリングすると、ライン上のすべてのポイントの正確なX、Y位置を決定できます。これは、他のオブジェクトの位置が楕円の位置と方向に依存する場合に便利です。
コードの例を次に示します。
for (var i = 0 * Math.PI; i < 2 * Math.PI; i += 0.01 ) {
xPos = centerX - (radiusX * Math.sin(i)) * Math.sin(rotationAngle * Math.PI) + (radiusY * Math.cos(i)) * Math.cos(rotationAngle * Math.PI);
yPos = centerY + (radiusY * Math.cos(i)) * Math.sin(rotationAngle * Math.PI) + (radiusX * Math.sin(i)) * Math.cos(rotationAngle * Math.PI);
if (i == 0) {
cxt.moveTo(xPos, yPos);
} else {
cxt.lineTo(xPos, yPos);
}
}
こちらのインタラクティブな例をご覧ください: http://www.scienceprimer.com/draw-oval-html5-canvas
楕円を確実に再現するには、4つのベジェ曲線(およびマジックナンバー)が必要です。こちらをご覧ください:
www.tinaja.com/glib/ellipse4.pdf
2つのベジェは、楕円を正確に再現しません。これを証明するには、同じ高さと幅で上記の2つのベジェソリューションのいくつかを試してください-理想的には円に近いはずですが、そうではありません。彼らはまだ楕円形に見えるでしょう。
これが機能するはずです。
コードは次のとおりです。
function ellipse(cx, cy, w, h){
var ctx = canvas.getContext('2d');
ctx.beginPath();
var lx = cx - w/2,
rx = cx + w/2,
ty = cy - h/2,
by = cy + h/2;
var magic = 0.551784;
var xmagic = magic*w/2;
var ymagic = h*magic/2;
ctx.moveTo(cx,ty);
ctx.bezierCurveTo(cx+xmagic,ty,rx,cy-ymagic,rx,cy);
ctx.bezierCurveTo(rx,cy+ymagic,cx+xmagic,by,cx,by);
ctx.bezierCurveTo(cx-xmagic,by,lx,cy+ymagic,lx,cy);
ctx.bezierCurveTo(lx,cy-ymagic,cx-xmagic,ty,cx,ty);
ctx.stroke();
}
また、不均一なスケーリングを使用してみることもできます。 XスケーリングとYスケーリングを提供できるため、XスケーリングまたはYスケーリングを他のスケーリングよりも大きく設定し、円を描くだけで楕円ができます。
私は少し一般的な楕円を望んでおらず、楕円のより大きな半軸と偏心度データしか持っていない人々のために、 このコード (Andrew Staroscikによって部分的に提示された)を少し適応させました(良いたとえば、軌道をプロットする天文のJavaScript玩具の場合)。
ここで、i
のステップを調整して図面の精度を高めることができることを思い出してください。
/* draw ellipse
* x0,y0 = center of the ellipse
* a = greater semi-axis
* exc = ellipse excentricity (exc = 0 for circle, 0 < exc < 1 for ellipse, exc > 1 for hyperbole)
*/
function drawEllipse(ctx, x0, y0, a, exc, lineWidth, color)
{
x0 += a * exc;
var r = a * (1 - exc*exc)/(1 + exc),
x = x0 + r,
y = y0;
ctx.beginPath();
ctx.moveTo(x, y);
var i = 0.01 * Math.PI;
var twoPi = 2 * Math.PI;
while (i < twoPi) {
r = a * (1 - exc*exc)/(1 + exc * Math.cos(i));
x = x0 + r * Math.cos(i);
y = y0 + r * Math.sin(i);
ctx.lineTo(x, y);
i += 0.01;
}
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;
ctx.closePath();
ctx.stroke();
}
私の解決策は、これらすべてとは少し異なります。もっとも近いと思うのは、上記で最も投票された答えだと思いますが、この方法は少しわかりやすく、理解しやすいと思います。
http://jsfiddle.net/jaredwilli/CZeEG/4/
function bezierCurve(centerX, centerY, width, height) {
con.beginPath();
con.moveTo(centerX, centerY - height / 2);
con.bezierCurveTo(
centerX + width / 2, centerY - height / 2,
centerX + width / 2, centerY + height / 2,
centerX, centerY + height / 2
);
con.bezierCurveTo(
centerX - width / 2, centerY + height / 2,
centerX - width / 2, centerY - height / 2,
centerX, centerY - height / 2
);
con.fillStyle = 'white';
con.fill();
con.closePath();
}
そして、次のように使用します:
bezierCurve(x + 60, y + 75, 80, 130);
QuadraticCurveToを使用して失敗する試みとともに、フィドルにはいくつかの使用例があります。
上記のベジェ曲線ソリューションが好きです。スケールは線幅にも影響することに気づいたので、高さよりも広い楕円を描画しようとすると、上下の「辺」が左右の「辺」よりも薄く表示されます...
良い例は次のとおりです。
ctx.lineWidth = 4;
ctx.scale(1, 0.5);
ctx.beginPath();
ctx.arc(20, 20, 10, 0, Math.PI * 2, false);
ctx.stroke();
楕円の山と谷の線の幅が、左右の頂点(アピ??)の半分の幅であることに注意してください。
ChromeおよびOpera support ellipse canvas 2dコンテキストのメソッドですが、IE、Edge、Firefox、Safariはサポートしていません。
JSで楕円法を実装するか、サードパーティのポリフィルを使用できます。
ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
使用例:
ctx.ellipse(20, 21, 10, 10, 0, 0, Math.PI*2, true);
canvas-5-polyfill を使用して、楕円法を提供できます。
または、いくつかのjsコードを貼り付けて、省略メソッドを提供します。
if (CanvasRenderingContext2D.prototype.ellipse == undefined) {
CanvasRenderingContext2D.prototype.ellipse = function(x, y, radiusX, radiusY,
rotation, startAngle, endAngle, antiClockwise) {
this.save();
this.translate(x, y);
this.rotate(rotation);
this.scale(radiusX, radiusY);
this.arc(0, 0, 1, startAngle, endAngle, antiClockwise);
this.restore();
}
}
はい、2つのベジェ曲線で可能です-簡単なチュートリアル/例です: http://www.williammalone.com/briefs/how-to-draw-ellipse-html5-canvas/
誰も簡単なquadraticCurveTo
を使用したアプローチを思いついていないので、そのためのソリューションを追加しています。 @Steveの answer のbezierCurveTo
呼び出しを次のように置き換えるだけです:
ctx.quadraticCurveTo(x,y,xm,y);
ctx.quadraticCurveTo(xe,y,xe,ym);
ctx.quadraticCurveTo(xe,ye,xm,ye);
ctx.quadraticCurveTo(x,ye,x,ym);
closePath
も削除できます。しかし、楕円形は少し異なって見えます。
これにより、楕円のセグメントを描画することもできます。
function ellipse(color, lineWidth, x, y, stretchX, stretchY, startAngle, endAngle) {
for (var angle = startAngle; angle < endAngle; angle += Math.PI / 180) {
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineTo(x + Math.cos(angle) * stretchX, y + Math.sin(angle) * stretchY)
ctx.lineWidth = lineWidth
ctx.strokeStyle = color
ctx.stroke()
ctx.closePath()
}
}
これは、形状のような楕円を作成する別の方法です。「fillRect()」関数を使用しますが、fillRect()関数の引数を変更するために使用できます。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Sine and cosine functions</title>
</head>
<body>
<canvas id="trigCan" width="400" height="400"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("trigCan"), ctx = canvas.getContext('2d');
for (var i = 0; i < 360; i++) {
var x = Math.sin(i), y = Math.cos(i);
ctx.stroke();
ctx.fillRect(50 * 2 * x * 2 / 5 + 200, 40 * 2 * y / 4 + 200, 10, 10, true);
}
</script>
</body>
</html>
これは、SVGの楕円弧と同じ値を使用する、私が書いた関数です。 X1とY1は最後の座標、X2とY2は終了座標、半径は数値、時計回りはブール値です。また、キャンバスコンテキストが既に定義されていることを前提としています。
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);
}
楕円を長方形の内側に完全に収めたい場合は、次のようになります。
_function ellipse(canvasContext, x, y, width, height){
var z = canvasContext, X = Math.round(x), Y = Math.round(y), wd = Math.round(width), ht = Math.round(height), h6 = Math.round(ht/6);
var y2 = Math.round(Y+ht/2), xw = X+wd, ym = Y-h6, yp = Y+ht+h6, cs = cards, c = this.card;
z.beginPath(); z.moveTo(X, y2); z.bezierCurveTo(X, ym, xw, ym, xw, y2); z.bezierCurveTo(xw, yp, X, yp, X, y2); z.fill(); z.stroke();
return z;
}
_
canvasContext.fillStyle = 'rgba(0,0,0,0)';
がこのデザインで塗りつぶされていないことを確認してください。