Question Comment dessiner un ovale en html5 canvas?


Il ne semble pas y avoir de fonction native pour dessiner une forme ovale. Aussi je ne cherche pas la forme d'œuf.

Est-il possible de dessiner un ovale avec 2 courbes bezier? Quelqu'un a expié avec ça?

Mon but est de dessiner des yeux et d'utiliser des arcs. Merci d'avance.

Solution

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

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

67
2018-01-31 18:34


origine


Réponses:


mises à jour:

  • la méthode de mise à l'échelle peut affecter l'apparence de la largeur de trait
  • la méthode de mise à l'échelle effectuée correctement peut conserver la largeur de trait intacte
  • toile a la méthode ellipse que Chrome prend désormais en charge
  • ajout de nouveaux tests à JSBin

Exemple de test JSBin (mis à jour pour tester les réponses des autres pour comparaison)

  • Bezier - dessine en fonction du coin supérieur gauche contenant rect et width / height
  • Bézier avec centre - dessiner en fonction du centre et de la largeur / hauteur
  • Arcs et mise à l'échelle - dessiner en fonction du cercle de dessin et de la mise à l'échelle
  • Courbes quadratiques - dessiner avec des quadratiques
    • test semble ne pas tirer tout à fait la même chose, peut être mise en œuvre
    • voir huîtres répondre
  • Canvas Ellipse - en utilisant la méthode ellipse () standard du W3C
    • test semble ne pas tirer tout à fait la même chose, peut être mise en œuvre
    • voir Loktar's répondre

Original:

Si vous voulez un ovale symétrique, vous pouvez toujours créer un cercle de largeur, puis le redimensionner à la hauteur souhaitée (modifier: remarquez que cela affectera l'apparence de la largeur de trait - voir la réponse de acdameli], mais si vous voulez un contrôle total de l'ellipse, utilisez les courbes bezier.

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

101
2018-01-31 19:56



Voici une version simplifiée des solutions ailleurs. Je dessine un cercle canonique, traduit et redimensionne et puis pointe.

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

43
2017-12-04 02:41



L'approche de la courbe de bezier est idéale pour les ovales simples. Pour plus de contrôle, vous pouvez utiliser une boucle pour dessiner une ellipse avec différentes valeurs pour le rayon x et y (rayons, rayons?).

L'ajout d'un paramètre rotationAngle permet à l'ovale de pivoter autour de son centre sous n'importe quel angle. Des ovales partiels peuvent être dessinés en modifiant la plage (var i) sur laquelle la boucle s'exécute.

Le rendu de l'ovale de cette manière vous permet de déterminer l'emplacement exact de x, y de tous les points de la ligne. Ceci est utile si la position d'autres objets dépend de l'emplacement et de l'orientation de l'ovale.

Voici un exemple du 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 un exemple interactif ici: http://www.scienceprimer.com/draw-oval-html5-canvas


15
2018-03-09 01:56



Vous avez besoin de 4 courbes bezier (et un nombre magique) pour reproduire de manière fiable une ellipse. Vois ici:

www.tinaja.com/glib/ellipse4.pdf

Deux beziers ne reproduisent pas avec précision une ellipse. Pour le prouver, essayez certaines des deux solutions ci-dessus avec la même hauteur et la même largeur - elles devraient idéalement s'approcher d'un cercle mais elles ne le seront pas. Ils auront toujours l'air ovale, ce qui prouve qu'ils ne font pas ce qu'ils sont censés faire.

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


}

11
2017-10-07 19:57



Vous pouvez également essayer d'utiliser une mise à l'échelle non uniforme. Vous pouvez fournir une mise à l'échelle X et Y, par conséquent, définissez simplement une échelle X ou Y plus grande que l'autre et tracez un cercle et vous obtenez une ellipse.


11
2018-01-31 19:59



J'ai fait une petite adaptation de ce code (partiellement présenté par Andrew Staroscik) pour peoplo qui ne veut pas d'une ellipse si générale et qui n'a que le plus grand demi-axe et les données d'excentricité de l'ellipse (bon pour les jouets javascript astronomiques par exemple).

Ici, vous vous souvenez que l'on peut adapter les étapes i avoir une plus grande précision dans le dessin:

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

8
2017-07-07 16:23



Il y a maintenant un natif ellipse fonction pour la toile, très similaire à la fonction arc bien que maintenant nous avons deux valeurs de rayon et une rotation qui est génial.

ellipse (x, y, radiusX, radiusY, rotation, startAngle, endAngle, dans le sens inverse des aiguilles d'une montre)

Démo en direct

ctx.ellipse(100, 100, 10, 15, 0, 0, Math.PI*2);
ctx.fill();

Semble seulement fonctionner dans Chrome actuellement


6
2018-04-20 16:18



Ma solution est un peu différente de celles-ci. Plus proche, je pense que la réponse la plus votée est ci-dessus, mais je pense que cette manière est un peu plus propre et plus facile à comprendre.

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

Et puis utilisez-le comme ceci:

bezierCurve(x + 60, y + 75, 80, 130);

Il y a quelques exemples d'utilisation dans le violon, ainsi qu'une tentative infructueuse d'en créer une avec quadraticCurveTo.


4
2017-12-16 12:39