Look at our four-line map from the last chapter. The lines are beautiful — parallel, glowing, smoothly splitting
at junctions. But the stations are still plain white circles sitting on the centerline, ignoring the colored
tracks flowing around them. The stations haven't caught up with the lines.
Real transit maps use different station markers depending on context. A minor stop on a single line gets a small
dot. A major interchange where four lines cross gets a large elongated shape — a pill — that
physically spans all the tracks, with colored indicators showing which lines stop there.
In this chapter we build three types of station markers, choosing the right one automatically based on how many
lines serve the station.
Type 1: The Simple Dot
For stations served by a single line, a small circle is enough. We've been drawing these since Chapter 1:
The top row shows the three station types side by side. The bottom row shows how the pill is constructed in four
steps: tracks → pill rectangle on top → colored dots inside → label below.
The pill is just an SVG <rect> with rx/ry set to half its width,
giving it fully rounded ends. Its height is computed from the number of lines × spacing, plus padding. The
colored dots are tiny circles positioned at each line's offset within the pill.
Orienting the Pill
On a horizontal track, the pill is vertical — perpendicular to the direction of travel. On a diagonal track, the
pill rotates to stay perpendicular. This is the same "perpendicular to the track" principle from Chapters 2 and
4.
The drawStation() function takes a position, a track angle, and the number of lines. It creates the
pill using SVG's transform="rotate(...)" and places colored dots along the perpendicular axis. The
same function handles all three angles without any special cases.
The Automatic Station Renderer
Now let's put it together — a function that automatically chooses the right station type based on the data:
Each station now renders differently based on its data. Westfield and Park (1 line each) get simple dots.
Riverside (2 lines) gets a plain pill. Old Town (3 lines) and Central (4 lines) get pills with colored transfer
dots inside. The decision is automatic — the renderer just checks station.lines.length.
The Rule
1 line → small circle.
2 lines → pill (no dots — the two line colors are visible on either side).
3+ lines → pill with colored transfer dots inside.
This mirrors the convention used by most real-world transit maps. The threshold between "dot" and "pill" is a
design choice — some systems use pills for all multi-line stations, others only for major interchanges. Adjust
to taste.
The drawStation() Function
Let's extract the automatic station renderer into a clean, reusable function:
The drawStation() function encapsulates all the logic: position, angle, line colors, spacing, and
optional terminus flag. It returns the SVG string for the appropriate marker type. Combined with
smoothPath() from Chapter 3 and the offset logic from Chapter 4, we now have the three core
rendering functions:
smoothPath(points) — draws a smooth curve through stations
perpXY(ax, ay, bx, by, offset) — computes parallel line displacement
drawStation(x, y, angle, colors, spacing) — renders the right station marker
These three functions, plus the getSegmentLines() lookup from Chapter 4, are the entire rendering
engine. Everything from here on is applying them to increasingly realistic data.
What We've Learned
Stations aren't just dots. They're data-driven markers that communicate how many lines serve them and which
lines those are. The visual language is simple — dots for minor stops, pills for multi-line stations, colored
dots inside pills for major interchanges — and the rendering function adapts automatically based on the
station's line count.
The perpendicular-to-track principle appears for the third time: label placement (Ch.2), parallel line offset
(Ch.4), and now pill orientation and dot placement (Ch.5). It's the one geometric idea you need for transit
maps.
Next: what happens at junctions where lines meet, split, and merge in more complex ways.