How to draw an oval in html5 canvas?
updates:
- scaling method can affect stroke width appearance
- scaling method done right can keep stroke width intact
- canvas has ellipse method that Chrome now supports
- added updated tests to JSBin
JSBin Testing Example (updated to test other's answers for comparison)
- Bezier - draw based on top left containing rect and width/height
- Bezier with Center - draw based on center and width/height
- Arcs and Scaling - draw based on drawing circle and scaling
- see Deven Kalra's answer
- Quadratic Curves - draw with quadratics
- test appears to not draw quite the same, may be implementation
- see oyophant's answer
- Canvas Ellipse - using W3C standard ellipse() method
- test appears to not draw quite the same, may be implementation
- see Loktar's answer
Original:
If you want a symmetrical oval you could always create a circle of radius width, and then scale it to the height you want (edit: notice this will affect stroke width appearance - see acdameli's answer), but if you want full control of the ellipse here's one way using bezier curves.
<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>
Canvas: arc(75,75,50,0,3.1415,true) draws oval instead of circle
If you change this line:
<canvas id=c1 style="width:400;height:400">
to:
<canvas id=c1 width=400 height=400></canvas>
it should work. Don't use CSS to set Canvas sizes as this only affects the element but not the bitmap itself. For canvas you need to use it's dedicated properties (width/height) to also set the bitmap size or the bitmap is just stretched/scaled to match the size of the element.
The default size of canvas if not specified is 300x150 pixels. In this case those pixels are stretched (as an image) to 400x400 which is why you get an oval instead.
How to draw a circle in HTML5 Canvas using JavaScript?
Here is how to draw a circle using JavaScript in HTML5:
const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
body {
margin: 0px;
padding: 0px;
}
<canvas id="myCanvas" width="578" height="200"></canvas>
Drawing multiple oval shapes on HTML canvas using JavaScript having an extra line
You are missing the context.beginPath
. Please see this JSFIddle: https://jsfiddle.net/zwcd7hcw/
function drawOvalShape(context, center_x, center_y, width, height){
context.beginPath()
context.ellipse(center_x, center_y, width, height, 90 * Math.PI/180, 0, 2 * Math.PI);
context.stroke();
}
var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); var center_x = 200; var center_y = 100; var width = 100; var height = 200; drawOvalShape(context, 200, 100, 100, 200); drawOvalShape(context, 200, 100, 80, 180); drawOvalShape(context, 200, 100, 60, 160); drawOvalShape(context, 200, 100, 40, 140); drawOvalShape(context, 200, 100, 20, 120);
function drawOvalShape(context, center_x, center_y, width, height){ context.beginPath() context.ellipse(center_x, center_y, width, height, 90 * Math.PI/180, 0, 2 * Math.PI);
context.stroke(); }
<canvas id="myCanvas" width="400" height="200" style="border:1px solid #000000;"></canvas>
Examples of the 3 ways to draw a circle on HTML5 canvas
It's all based on the same principle: You can draw a circle or ellipse by taking their parametric formula (x²+y² = some constant, and x²/a + y²/b = some constant, respectively), and joining up valid points for those formulae. Somehow. You can simply pick points that are so close that there's nothing "to join" since subsequent points are literally "the next pixel" (which is what arcTo does), but you can also space them further apart, and then you can join things up using:
- lines
- quadratic bezier curves
- cubic bezier curve
- literally any kind of curve, since you know all the points it needs to pass through
The challenge is not in joining up the points, it's knowing how far apart the points can be before things start to look pretty shitty.
For instance, for quadratic Bezier curves, you need 8 or more curves for things to look decent. Fewer than that, and it starts to look bad. For cubic Bezier curves, 4 is usually enough. For other curve types it really depends on the maths, which either you, or someone else, will have to work out to determine how many points you're going to need for things to look right.
But really, use arcTo, or even circle() and ellipse() if the programming language you're using has those. Don't approximate if you can just directly draw what you needed to draw.
How to draw a smooth oval in canvas
One problem is in the nature of your display screen...
Since pixels are rectangles and you're drawing a curve, your result will have "jaggies" as the curve tries to fit itself in rectangular spaces.
You can use an optical illusion to trick the eye into seeing a less jagged oval.
An optical trick:
Reduce the contrast between the background color and the oval color.
This is not a cure...the jaggies are still there.
But the eye recognizes less contrast and perceives the oval as more smooth.
So if your design accommodates this style change, this optical illusion might help.
Here's code and a Fiddle: http://jsfiddle.net/m1erickson/vDWR3/
var cx=180;
var cy=200;
var w=300;
var h=250;
// Start with a less-contrasting background
ctx.fillStyle="#ddd";
ctx.fillRect(0,0,canvas.width,canvas.height);
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.fillStyle="#555";
ctx.strokeStyle=ctx.fillStyle;
ctx.lineWidth=1.5;
ctx.stroke();
Related Topics
Show Hide Divs on Click in HTML and CSS Without Jquery
Uploading 'Canvas' Image Data to the Server
How to Get the Background Color of an HTML Element
How to Get Query String Value from Script Path
How to Retrieve the Display Property of a Dom Element
Change CSS of Selected Text Using JavaScript
Convert Rgb to Rgba Over White
Why Is My Variable Unaltered After I Modify It Inside of a Function? - Asynchronous Code Reference
For-Each Over an Array in JavaScript
How to Display JavaScript Variables in a HTML Page Without Document.Write
How to Draw an Oval in Html5 Canvas
Convert HTML to Data:Text/Html Link Using JavaScript
How to Escape Quotes in HTML Attribute Values
Why the Onclick Element Will Trigger Twice For Label Element
How to Generate a Simple Popup Using Jquery
What Is the Cleanest Way to Disable CSS Transition Effects Temporarily