Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~23 min· topic 2 of 7

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.

what each shape needswhole filehtml
<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. 1

    Make a pill

    In the first example, change rx="14" to rx="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. 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 says teal 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. 3

    Give the polygon a second look

    Change polygon to polyline for 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, add fill="none".

Code & diagrams

The six shapes, and paint order New tab

Plain SVG markup, no script needed to draw it. The script only reports the order. Each shape carries only the attributes it needs.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Paint order: rect rect circle ellipse line polyline polygon rect rect rect rect
Missing, odd and wrong attributes New tab

A bad value prints a real browser error right after its line. Chromium's wording is shown; Firefox and Safari phrase these errors differently.

Preview

Press Run to see the page.

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

terminal
$ Console
── what you'll see ──
Error: <rect> attribute width: A negative value is not valid. ("-80")
Paint order: rect rect circle ellipse line polyline polygon rect rect rect rect

Break #2

Forget the stroke on a line

In the first example, delete stroke="#264653" stroke-width="4" from the <line>.

terminal
$ Preview and Console
── what you'll see ──
The diagonal line at the top right is gone. The Console prints the same Paint order as before, and no error: the line still exists, but a line with no stroke paints nothing.

Break #3

Forget fill="none" on a polyline

In the first example, delete fill="none" from the <polyline>.

terminal
$ Preview
── what you'll see ──
The open zig-zag becomes two black triangles with a dark outline, because the browser fills the shape as if its two ends were joined. No error is printed.

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 rx to half the width and ry to half the height, so a huge rx on a 40 by 20 box cannot make the corners overlap. It gives the most rounded corners the box allows, not an error.

  • ▸

    A line is the same drawing as a path with two points (Topic 1.3). A polyline is a path made only of L commands. Libraries such as D3 draw lines as paths 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. 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. 2

    The six shapes and what each needs. rect needs x, y, width, height. circle needs cx, cy (the centre) and r (the radius). ellipse needs cx, cy, rx, ry. line needs x1, y1, x2, y2. polyline and polygon take points, a list of x,y pairs. A polygon joins its last point back to its first; a polyline does not.

  3. 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 rect with no colours is a black box, a polyline with no fill="none" is a black filled area, and a line with no stroke is invisible. Topic 1.5 covers colours in full.

  4. 4

    Rounded corners. A rect takes rx and ry, the radii of its corners. Giving only rx makes ry the same. A radius larger than half the side is cut back to half, so rx equal to half the height gives a pill with round ends. Charts use a small rx to soften bars.

  5. 5

    A missing attribute counts as 0, with no error. A rect without width has a width of 0 and is not drawn. A circle without r has radius 0. A circle without cx is centred at x = 0. A line without x2 ends at x = 0, so it runs from its start to the left edge. A bad number is another story: a negative width, a negative r, the text NaN or an empty value each print a console error and the shape is not drawn. The second example prints all of these.

  6. 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-index for 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

01

Which attributes does each of the six basic shapes need?

02

Why is a line with no stroke invisible, and what does the browser print about it?

03

How does the browser decide which shape is on top, and how do you change it?

04

What happens with a negative width, and what with a missing width?

Practice

01

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?

02

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