76 votes

Comment dessiner un ovale en toile html5?

Il ne semble pas être une fonction native pour dessiner un ovale en forme. Aussi, je ne suis pas à la recherche de la forme ovoïde.

Est-il possible de tracer un ovale avec 2 courbes de bézier? Quelqu'un expierenced avec qui?

Mon but est de dessiner des yeux et en fait je suis juste en utilisant des arcs. Merci à l'avance.

Solution

Donc scale() modifie la mise à l'échelle pour toutes les prochaines formes. Save() enregistre les paramètres avant et de la restauration est utilisé pour restaurer les paramètres de dessiner de nouvelles formes sans mise à l'échelle.

Grâce à Jani

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();

109voto

Steve Tranby Points 3759

mises à jour:

  • méthode de mise à l'échelle peut affecter la largeur du contour de l'apparence
  • mise à l'échelle de la méthode fait droit peut garder la largeur du trait intacte
  • la toile a ellipse méthode que google Chrome prend désormais en charge
  • ajoutée à jour des tests de JSBin

JSBin Test Exemple (mis à jour afin de tester d'autres réponses pour la comparaison)

  • De bézier - tirage basé sur en haut à gauche contenant rect et la largeur/hauteur
  • De bézier avec le Centre - tirage basé sur le centre et la largeur/hauteur
  • Les Arcs et la mise à l'Échelle - tirage basé sur le dessin du cercle et de la mise à l'échelle
  • Quadratique Courbes de dessiner avec quadratics
    • test semble pas attirer tout à fait la même, peut être mise en œuvre
    • voir oyophant de réponse
  • Toile d'Ellipse à l'aide de standards du W3C ellipse() la méthode
    • test semble pas attirer tout à fait la même, peut être mise en œuvre
    • voir Loktar de réponse

Origine:

Si vous voulez un symétrique de forme ovale, vous pouvez toujours créer un cercle d'un rayon de largeur, et ensuite échelle à la hauteur que vous voulez (edit: avis cela va affecter la largeur du contour de l'apparence - voir acdameli de réponse), mais si vous voulez le plein contrôle de l'ellipse voici un moyen à l'aide de courbes de bézier.

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

45voto

Deven Kalra Points 261

Voici une version simplifiée des solutions ailleurs. Je dessine un cercle canonique, traduis et redimensionne puis je caresse.

 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();
}
 

16voto

Andrew Staroscik Points 760

La courbe de bézier approche est grand pour de simples ovales. Pour plus de contrôle, vous pouvez utiliser une boucle pour dessiner une ellipse avec des valeurs différentes pour le rayon x et y (les rayons, les rayons?).

L'ajout d'un rotationAngle paramètre permet à l'ovale être mis en rotation autour de son centre par n'importe quel angle. Partielle ovales peuvent être tirées par un changement de gamme (var i) au cours de laquelle la boucle s'exécute.

Le rendu de l'ovale de cette façon, vous permet de déterminer l'exacte x,y de l'emplacement de tous les points sur la ligne. Ceci est utile si la position des autres objets dépendent de l'emplacement et de l'orientation de l'ovale.

Voici un exemple de code:

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);
    }
}

Voir une présentation interactive ici: http://www.scienceprimer.com/draw-oval-html5-canvas

11voto

Jani Hartikainen Points 23183

Vous pouvez également essayer d'utiliser une mise à l'échelle non uniforme. Vous pouvez fournir une mise à l'échelle X et Y, il vous suffit donc de définir une échelle X ou Y plus grande que l'autre, de tracer un cercle et d'obtenir une ellipse.

11voto

Alankar Misra Points 81

Vous avez besoin de 4 courbes de bézier (et un nombre magique) pour reproduire de manière fiable une ellipse. Voir ici:

www.tinaja.com/glib/ellipse4.pdf

Deux beziers ne pas reproduire avec précision une ellipse. Pour le prouver, essayer quelques-uns des 2 courbes de bézier solutions ci-dessus, avec une égale hauteur et la largeur - ils devraient idéalement se rapprocher d'un cercle, mais ils ne seront pas. Ils vont encore look ovale qui va à prouver qu'ils ne font pas ce qu'ils sont censés.

Voici quelque chose qui devrait fonctionner:

http://jsfiddle.net/BsPsj/

Voici le code:

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();


}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X