Chapter Seven

A Piece of the Real Thing

Everything we've built, applied to a network that feels real.

For six chapters we've been building with toy examples — three stations here, four lines there. Each example was designed to illustrate one concept. Now we put them all together and render a network fragment complex enough to feel like a real transit system.

This is Metro Lumina — our fictional metro. It has four metro lines and one tram line, a shared central corridor, branches going north, south, and east, a perpendicular crossing, and a tram that runs along the waterfront. It's not based on any specific city, but it has the structural complexity of a real mid-sized system.

We'll build it in one editor, using every function from the previous chapters. The code is longer than anything we've written so far — but it's all familiar pieces.

Live Editor — Metro Lumina: a realistic network fragment

That's a metro map. Four metro lines and a tram, with shared corridors, branches, a crossing, and twenty stations. Built entirely from the functions we developed in Chapters 3 through 5.

Let's walk through what's happening:

The Shared Trunk

Lines L1, L2, and L3 share the central corridor from Riverside through Market Square, Central, and Old Town. That's three parallel colored lines — amber, pink, and blue — running together. The corridor is the visual spine of the network.

The Northern Branch

L1 and L2 share a northern branch from Northgate up to Hillcrest. At Northgate, L3 joins from the west (arriving from Westfield/Airport). The three-line corridor forms naturally at Riverside where all three paths converge.

The Split at Old Town

At Old Town, the three-line corridor breaks apart. L1 and L3 continue east to Gardens and Harbour. L2 turns south to University and Stadium. The fork is smooth — L2 peels away with a bezier curve because its next station (University) is directly below.

The Perpendicular Crossing

L4 (green) runs north-south, crossing the central corridor at Central station. The station marker at Central is a large pill with four transfer dots (amber, pink, blue, green) — showing all four metro lines that serve it.

The Tram

T1 (purple, dashed line) runs along the waterfront from Marina through Pier 7, connecting to Harbour (shared with L1 and L3) and continuing to Beach. The dashed stroke distinguishes tram from metro.

What Didn't Change

The rendering engine is identical to Chapter 6. Not a single function was modified to handle this more complex network. The only new thing is data — more stations, more lines, more connections. The system scales by adding data, not by adding code.

That's the payoff of the connect-the-dots architecture. The complexity lives in the data, not in the renderer.

Design Decisions

A few choices we made for Metro Lumina that apply to any transit map:

Schematic vs Geographic

Station positions are schematic — arranged for readability, not geographic accuracy. Central is in the center of the canvas. The northern branch goes straight up. The eastern branch goes straight right. Real geography would overlap stations and create messy angles. Schematic layout sacrifices geographic truth for visual clarity.

Label Placement Is Manual

We hand-positioned every label with specific offsets. Automatic label placement algorithms exist, but for a network this size, manual positioning takes five minutes and produces better results. This is a pragmatic choice: automate the hard geometry (parallel lines, bezier curves), hand-tune the easy aesthetics (label positions).

Tram vs Metro Distinction

The dashed line for the tram isn't a technical necessity — it's a design convention. Most transit maps visually distinguish service types. Dashed for tram/light rail, solid for metro/heavy rail. Some systems use thinner strokes for trams instead. The key is consistency.

The Data Structure

Look at the data at the top of the editor. The entire network is defined by two objects:

S — a map of station IDs to positions and names. Twenty stations, each with an x, y, and name.

lines — an array of line objects, each with an id, color, and stops (ordered array of station IDs).

That's it. No junction definitions, no corridor mappings, no path geometry. The rendering functions derive everything else from these two data structures.

Try This

Add a new station to the network. In the S object, add:
campus: { name:"Campus", x:530, y:300 }
Then extend L2's stops from ["...","stadium"] to ["...","stadium","campus"].

A new station appears. L2 extends to it. The station gets a simple dot (single line). The bezier curve from Stadium to Campus draws itself. No rendering code was touched — you only added data.

This is the network we'll keep using for the rest of the guide. In the next chapter, we'll show how a data structure like this can be generated from real-world GTFS transit data — turning any city's published feed into a map.

Drawing Transit — An open guide to programmatic transit maps