Es scheint keine native Funktion zu geben, um eine ovale Form zu zeichnen. Auch ich suche nicht die Eiform.
Ist es möglich, ein Oval mit 2 Bezierkurven zu zeichnen? Hat das jemand erlebt?
Mein Zweck ist es, einige Augen zu zeichnen und tatsächlich benutze ich nur Bögen. Danke im Voraus.
Lösung
Also ändert scale () die Skalierung für alle nächsten Formen. Speichern () speichert die Einstellungen vor und Wiederherstellen wird verwendet, um die Einstellungen wiederherzustellen und neue Formen ohne Skalierung zu zeichnen.
Danke an 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();
javascript
html
canvas
Tammo
quelle
quelle
restore()
vorher sagenstroke()
, wird es die Linie nicht verzerren, wie Johnathan Hebert im Kommentar zu Steve Tranbys Antwort unten erwähnte. Auch dies ist unnötig und falsch zu verwendenclosePath()
. Solch eine missverstandene Methode ... stackoverflow.com/questions/10807230/…Antworten:
Aktualisierung:
JSBin-Testbeispiel (aktualisiert, um die Antworten anderer zum Vergleich zu testen)
Original:
Wenn Sie ein symmetrisches Oval wünschen, können Sie jederzeit einen Kreis mit Radiusbreite erstellen und ihn dann auf die gewünschte Höhe skalieren ( Bearbeiten: Beachten Sie, dass dies das Erscheinungsbild der Strichbreite beeinflusst - siehe Antwort von acdameli). Wenn Sie jedoch die Ellipse vollständig steuern möchten Hier ist eine Möglichkeit, Bezierkurven zu verwenden.
<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>
quelle
scale
sie Schlaganfälle verzerren wird (siehe Antwort von acdameli).Hier ist eine vereinfachte Version von Lösungen an anderer Stelle. Ich zeichne einen kanonischen Kreis, übersetze und skaliere und streiche dann.
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(); }
quelle
context
Sie das schwere Heben mit machenscale
.Es gibt jetzt eine native Ellipsenfunktion für Leinwand, die der Bogenfunktion sehr ähnlich ist, obwohl wir jetzt zwei Radiuswerte und eine Drehung haben, die fantastisch ist.
Live-Demo
ctx.ellipse(100, 100, 10, 15, 0, 0, Math.PI*2); ctx.fill();
Scheint derzeit nur in Chrome zu funktionieren
quelle
Der Bezierkurvenansatz eignet sich hervorragend für einfache Ovale. Für mehr Kontrolle können Sie eine Schleife verwenden, um eine Ellipse mit unterschiedlichen Werten für den x- und y-Radius (Radien, Radien?) Zu zeichnen.
Durch Hinzufügen eines Rotationswinkel-Parameters kann das Oval um einen beliebigen Winkel um seine Mitte gedreht werden. Partielle Ovale können gezeichnet werden, indem der Bereich (var i) geändert wird, über den die Schleife läuft.
Wenn Sie das Oval auf diese Weise rendern, können Sie die genaue x, y-Position aller Punkte auf der Linie bestimmen. Dies ist nützlich, wenn die Position anderer Objekte von der Position und Ausrichtung des Ovals abhängt.
Hier ist ein Beispiel für den 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); } }
Ein interaktives Beispiel finden Sie hier: http://www.scienceprimer.com/draw-oval-html5-canvas
quelle
Sie benötigen 4 Bezierkurven (und eine magische Zahl), um eine Ellipse zuverlässig zu reproduzieren. Siehe hier:
www.tinaja.com/glib/ellipse4.pdf
Zwei Bezier reproduzieren eine Ellipse nicht genau. Um dies zu beweisen, probieren Sie einige der beiden oben genannten Bezier-Lösungen mit gleicher Höhe und Breite aus. Sie sollten sich idealerweise einem Kreis annähern, werden es aber nicht. Sie sehen immer noch oval aus, was beweist, dass sie nicht das tun, was sie sollen.
Hier ist etwas, das funktionieren sollte:
http://jsfiddle.net/BsPsj/
Hier ist der 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(); }
quelle
Sie können auch versuchen, eine ungleichmäßige Skalierung zu verwenden. Sie können eine X- und Y-Skalierung bereitstellen. Stellen Sie also einfach die X- oder Y-Skalierung größer als die andere ein, zeichnen Sie einen Kreis und Sie haben eine Ellipse.
quelle
Ich habe eine kleine Anpassung dieses Codes (teilweise von Andrew Staroscik vorgestellt) für Personen vorgenommen, die keine so allgemeine Ellipse wollen und nur die größere Halbachse und die Exzentrizitätsdaten der Ellipse haben (gut für astronomische Javascript-Spielzeuge, um Umlaufbahnen zu zeichnen , zum Beispiel).
Denken Sie daran, dass Sie die Schritte anpassen können, um
i
eine präzisere Zeichnung zu erzielen:/* 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(); }
quelle
Meine Lösung ist etwas anders als alle diese. Am nächsten ist meiner Meinung nach die am häufigsten gewählte Antwort, aber ich denke, dieser Weg ist ein bisschen sauberer und leichter zu verstehen.
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(); }
Und dann benutze es so:
bezierCurve(x + 60, y + 75, 80, 130);
Es gibt einige Anwendungsbeispiele in der Geige, zusammen mit einem fehlgeschlagenen Versuch, eines mit quadraticCurveTo zu erstellen.
quelle
Ich mag die Bezier-Kurvenlösung oben. Ich habe festgestellt, dass die Skalierung auch die Linienbreite beeinflusst. Wenn Sie also versuchen, eine Ellipse zu zeichnen, die breiter als hoch ist, erscheinen Ihre oberen und unteren "Seiten" dünner als Ihre linken und rechten "Seiten" ...
Ein gutes Beispiel wäre:
ctx.lineWidth = 4; ctx.scale(1, 0.5); ctx.beginPath(); ctx.arc(20, 20, 10, 0, Math.PI * 2, false); ctx.stroke();
Sie sollten beachten, dass die Breite der Linie am Gipfel und im Tal der Ellipse halb so breit ist wie an der linken und rechten Spitze (Spitzen?).
quelle
ctx.scale(0.5, 1);
Ja, es ist mit zwei Bezierkurven möglich - hier ein kurzes Tutorial / Beispiel: http://www.williammalone.com/briefs/how-to-draw-ellipse-html5-canvas/
quelle
Chrome und Opera unterstützen die Ellipsenmethode für den 2D-Canvas-Kontext, IE, Edge, Firefox und Safari unterstützen sie jedoch nicht.
Wir können die Ellipsenmethode von JS implementieren oder eine Polyfüllung von Drittanbietern verwenden.
Anwendungsbeispiel:
ctx.ellipse(20, 21, 10, 10, 0, 0, Math.PI*2, true);
Sie können eine Canvas-5-Polyfüllung verwenden , um eine Ellipsenmethode bereitzustellen.
Oder fügen Sie einfach einen js-Code ein, um die Ellipsenmethode bereitzustellen:
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(); } }
quelle
Dies ist eine weitere Möglichkeit, eine ellipsenähnliche Form zu erstellen, obwohl die Funktion "fillRect ()" verwendet wird. Dies kann verwendet werden, um die Argumente in der Funktion fillRect () zu ändern.
<!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>
quelle
Damit können Sie sogar Segmente einer Ellipse zeichnen:
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() } }
http://jsfiddle.net/FazAe/1/
quelle
Da niemand einen Ansatz mit dem Einfacheren gefunden hat, füge
quadraticCurveTo
ich eine Lösung dafür hinzu. Ersetzen Sie einfach diebezierCurveTo
Anrufe in der Antwort von @ Steve durch Folgendes :Sie können auch die entfernen
closePath
. Das Oval sieht allerdings etwas anders aus.quelle
Hier ist eine Funktion, die ich geschrieben habe und die dieselben Werte wie der Ellipsenbogen in SVG verwendet. X1 & Y1 sind die letzten Koordinaten, X2 & Y2 sind die Endkoordinaten, der Radius ist ein Zahlenwert und im Uhrzeigersinn ein Boolescher Wert. Es wird auch davon ausgegangen, dass Ihr Canvas-Kontext bereits definiert wurde.
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); }
quelle
Wenn Sie möchten, dass die Ellipse vollständig in ein Rechteck passt, ist dies wirklich so:
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; }
Stellen Sie sicher, dass Sie
canvasContext.fillStyle = 'rgba(0,0,0,0)';
dieses Design nicht ausfüllen.quelle