Topic 1.2
Basic Shapes
In one line
SVG has six basic shapes: rect, circle, ellipse, line, polyline and polygon. Each needs a few attributes; a missing one counts as 0 and usually draws nothing, a negative size is an error, and later shapes paint over earlier ones.
Think of it like this
A box of flat paper cut-outs. You have rectangles, circles, ovals, a strip, and zig-zag shapes. You lay them on a table one after another, and each new one covers whatever is under it. SVG works the same way: you place shapes by number, and the last one placed ends up on top.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- fill
- The colour inside a shape. The default is black.
- stroke
- The outline of a shape. The default is none, so a line without a stroke cannot be seen.
- radius
- The distance from the centre of a circle to its edge. Written r.
- points
- The list of corners of a polyline or polygon, written as x,y pairs such as
10,150 40,100 70,150. - paint order
- The order shapes are drawn in. Later shapes are drawn on top of earlier ones.
- polyline
- A shape made of straight segments through a list of points. It stays open.
- polygon
- Like a polyline, but the last point is joined back to the first, so it is closed.
Step by step
01Meet the six shapes
The first example draws every shape once, in plain SVG written straight into the page. This is the same markup you would paste into your own index.html.
The rect and the rounded rect both have 80 by 50 sizes; the second adds rx="14". The circle is centred at (240, 35) with radius 25. The ellipse is 80 wide and 40 tall, because rx is 40 and ry is 20.
<rect x="10" y="10" width="80" height="50"></rect>
<circle cx="240" cy="35" r="25"></circle>
<ellipse cx="320" cy="35" rx="40" ry="20"></ellipse>
<line x1="390" y1="10" x2="430" y2="60" stroke="black"></line>
<polyline points="10,150 40,100 70,150" fill="none" stroke="black"></polyline>
<polygon points="150,150 185,100 220,150"></polygon>02Open or closed
The zig-zag is a polyline: five points, four segments, left open. The triangle is a polygon: three points, three sides, because the last point joins the first. Both need points and nothing else.
The zig-zag has fill="none". Without it, the browser fills the open shape, as if its ends were joined by a straight line, and you get black triangles (Break it below).
03Leave things out and see what happens
The second example builds small SVGs with one attribute missing or wrong and prints each shape's bounding box. A rect with no width is 0 wide. A circle with no cx is centred at x = 0, so its box starts at −10. A line with no x2 runs from x = 50 to x = 0.
Some results are less obvious. An ellipse with only rx copies it into ry, giving a circle-shaped 60 by 60 box. A width of 50% means half of the SVG's width (100 here). A polygon with an odd number of coordinates ignores the last lonely number, and no error is printed.
04Wrong numbers are loud
Three bad widths follow in the Console: -20, abc and an empty string. Each prints an error from the browser and leaves the width at 0. The wording is the browser's own, so you can search for it when you meet it in real code: A negative value is not valid. or Expected length, "abc".
The most common real cause is a calculation that returned NaN or a negative number, such as a bar whose value is below the chart's minimum (Topic 0.2's Break it). Always read the Console when a shape is missing.
Try it yourself
- 1
Make a pill
In the first example, change
rx="14"torx="25". The rounded rectangle is 50 tall, so a corner radius of 25 is half the height: the two ends become half circles and the shape is a pill. - 2
Swap the paint order
Move the orange
<rect x="40" ...>line above the teal one at the left. Now teal covers orange there too (the caption under it still saysteal first, orange on top, so it is now wrong). Only the order in the markup changed, and the Console's paint order is the same list because both are rects: the visual result is what differs. - 3
Give the polygon a second look
Change
polygontopolylinefor the triangle, keeping its attributes. It now has only two sides drawn (no bottom edge), but the green fill still appears: the browser fills an open shape as if it were closed. To see the open outline alone, addfill="none".
Code & diagrams
Plain SVG markup, no script needed to draw it. The script only reports the order. Each shape carries only the attributes it needs.
Preview
Console
Nothing logged yet.Expected console output
Paint order: rect rect circle ellipse line polyline polygon rect rect rect rectA bad value prints a real browser error right after its line. Chromium's wording is shown; Firefox and Safari phrase these errors differently.
Preview
Console
Nothing logged yet.Expected console output
rect without width : x 10, width 0, height 30
circle without r : x 50, width 0, height 0
circle without cx : x -10, width 20, height 20
line without x2 : x 0, width 50, height 0
ellipse with only rx : x 20, width 60, height 60
rect width 50% : x 0, width 100, height 20
polygon, odd numbers : x 10, width 40, height 40
rect width -20 : x 0, width 0, height 20
Error: <rect> attribute width: A negative value is not valid. ("-20")
rect width abc : x 0, width 0, height 20
Error: <rect> attribute width: Expected length, "abc".
rect width empty : x 0, width 0, height 20
Error: <rect> attribute width: Unexpected end of attribute. Expected length, "".
A line with no stroke attribute has stroke: none
A polyline with no fill attribute has fill: rgb(0, 0, 0)Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Draw a negative width
In the first example, change the first rect to width="-80".
Break #2
Forget the stroke on a line
In the first example, delete stroke="#264653" stroke-width="4" from the <line>.
Break #3
Forget fill="none" on a polyline
In the first example, delete fill="none" from the <polyline>.
Myth vs fact
Myth
A line is visible once you give it coordinates.
Fact
A line with no stroke is invisible. Fill does not apply to it, and the default stroke is none.
Myth
A missing attribute is an error, so the Console will tell me.
Fact
A missing attribute counts as 0 and the Console stays silent. The second example shows a rect without width, a circle without r and a line without x2, all quiet. Only wrong values (negative, NaN, text, empty) print errors.
Myth
z-index puts one SVG shape in front of another.
Fact
SVG shapes ignore z-index. Their order in the markup is their order on screen: later is on top.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
An
<svg>can also hold HTML elements through<foreignObject>, but shapes are what the data-join in Phase 5 creates. For stacking, groups (<g>, Topic 1.6) let you move a whole layer, for example all labels, to the end in one step. - ▸
The browser limits
rxto half the width andryto half the height, so a hugerxon a 40 by 20 box cannot make the corners overlap. It gives the most rounded corners the box allows, not an error. - ▸
A
lineis the same drawing as apathwith two points (Topic 1.3). Apolylineis a path made only ofLcommands. Libraries such as D3 draw lines aspaths because paths can also bend (curves) and break (gaps). - ▸
Every shape is one DOM node. A few thousand SVG shapes are fine on modern computers, but the cost grows with the count: rendering, layout, memory and event handling are all per node. Topic 12.1 measures where SVG stops being a good choice.
Remember this
- 1
The problem this solves: a bar is a rectangle, a dot is a circle, a line chart is a polyline. To draw any chart you must know what each shape needs, what it does when you leave something out, and what the browser says when a number is wrong. Chart bugs are mostly one of these three.
- 2
The six shapes and what each needs.
rectneedsx,y,width,height.circleneedscx,cy(the centre) andr(the radius).ellipseneedscx,cy,rx,ry.lineneedsx1,y1,x2,y2.polylineandpolygontakepoints, a list ofx,ypairs. A polygon joins its last point back to its first; a polyline does not. - 3
Fill and stroke have defaults that surprise people. The fill is the inside colour and defaults to black. The stroke is the outline and defaults to none. So a
rectwith no colours is a black box, apolylinewith nofill="none"is a black filled area, and alinewith nostrokeis invisible. Topic 1.5 covers colours in full. - 4
Rounded corners. A
recttakesrxandry, the radii of its corners. Giving onlyrxmakesrythe same. A radius larger than half the side is cut back to half, sorxequal to half the height gives a pill with round ends. Charts use a smallrxto soften bars. - 5
A missing attribute counts as 0, with no error. A
rectwithoutwidthhas a width of 0 and is not drawn. Acirclewithoutrhas radius 0. A circle withoutcxis centred at x = 0. Alinewithoutx2ends at x = 0, so it runs from its start to the left edge. A bad number is another story: a negativewidth, a negativer, the textNaNor an empty value each print a console error and the shape is not drawn. The second example prints all of these. - 6
Paint order is document order. The browser paints shapes in the order they appear, so each one covers earlier ones. There is no
z-indexfor SVG shapes. To bring a shape to the front, move it later in the markup. Chart authors rely on this: gridlines first, bars next, labels last.
Explain it without notes
Which attributes does each of the six basic shapes need?
Why is a line with no stroke invisible, and what does the browser print about it?
How does the browser decide which shape is on top, and how do you change it?
What happens with a negative width, and what with a missing width?
Practice
Write the SVG markup for a bar chart bar for Monday: a rectangle 40 wide and 119.4 tall, standing on a baseline at y = 180, filled #e76f51, with its left edge at x = 30. What is its y?
A rectangle shows nothing and the Console is empty. List three attribute mistakes that cause this.
Trade-offs
- ↔
Writing SVG as markup in the page is easy to read and needs no script, but it is fixed. Creating shapes with JavaScript from data costs more code and lets the chart follow the data (Phase 3 and 5).
Done when you can
I can write the markup for any of the six shapes from memory.
I know the default fill (black) and stroke (none), and what that means for a line.
I can predict which shape is on top from the markup order.
I can tell a silent mistake (missing attribute) from a loud one (negative or NaN).