Unit 3 - Interlining with Branches

In this guide, we will cover standard 'common core' systems where multiple services share a core section and have branches outside of the core. For this case study, we will use the particularly nasty example of the UTA TRAX Light Rail system, where branches 'cross' other lines and where three different services share a core section of track.

Initial Setup

We will begin by placing all of our stations on a single line - we will use blue for now. Note just how many stations there are - we are combining three lines onto the same map, after all.

locknumstations and shifting stations

Now the real challenge begins. First, we will want to have stations rendering on top of one another to make better use of space. Since we have so many stations, we will therefore want to use locknumstations. This will set the spacing between stations such that it is 'as-if' there were only the specified number of stations on the map. Notably, the endpoint field of a stroke still uses the total number of stations on the map rather than this value for its actual location so we will need to do some approximation when we handle our strokes later on.

To get the number of stations to use, we will utilize the maximum possible number of stations any theoretical service can stop at. This means 9 stations from the southern branch of the Red Line, the 13 stations on the central core, and the 6 extra stations on the Green Line. This totals to 28 stations for now.

With that, we can also begin shifting stations around. We use the xshift field for stations to shift them by a set number of stations. Notably, this does mean that we will have some rather ugly shifts later on due to the complexity of the map. We have exactly 50 stations but since we're trying to fit them into a space assuming there are 28, there is no 'nice' conversion. Adding even more complexity, we will add two dummy stations with no name to our map. These will help with spacing, allowing for our diagonal lines to fit more nicely.

        {
            "stypeID": "STATION_TYPE_NONE",
            "stnnodes": [
            ]
        }

The specific locations for these dummy stations will be on the Blue Line between Midvale Fort Union and Fashion Place West (Blue Line link), between Millcreek and Central Pointe on the common core (Green Line link), and between Arena and North Temple Bridge on the common core (Blue Line link). The first is necessary to allow for nice spacing, while the second is necessary to prevent the Green Line's path from covering Millcreek's station name. The third allows for the Blue Line to not conflict with the other labels as it moves out to the top after Arena. This makes our final value for locknumstations 30, since two stations (albeit dummies) are being added to the common core.

Code for some of the stations has been provided below. For this example, we have removed the main 'line' to focus on the station positions themselves.

"stations": [
        {
            "name": ["Draper Town Center"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        ...
        {
            "name": ["Midvale Fort Union"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": [""],
            "stationtype": "STATION_TYPE_NONE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Daybreak Pkwy."],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9
        },
        ...
        {
            "name": ["Fashion Place West"],
            "stationtype": "STATION_TYPE_COMBINED",
            "icons": [
            ],
            "xshift": -9
        },
        ...
        {
            "name": ["West Valley Central"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "dy": -144,
            "xshift": -13
        },
        ...
        {
            "name": ["River Trail"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "dy": -144,
            "xshift": -13
        },
        {
            "name": [""],
            "stationtype": "STATION_TYPE_NONE",
            "icons": [
            ],
            "xshift": -9
        },
        {
            "name": ["Central Pointe"],
            "stationtype": "STATION_TYPE_COMBINED",
            "icons": [
                ["ICON_SLINE"]
            ],
            "xshift": -13
        },
        ...
        {
            "name": ["Library"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },

As you can see, the xshift field can get quite complicated. We will now explain how it works.

First we will look at Daybreak Pkwy. The xshift value is -9, since we are shifting the station (which would have been located where Fashion Place West currently is) left by 9 station units. This is because there were 8 + 1 dummy stations on the Blue Line beforehand. The -9 offset carries over to all future stations on the combined portion.

The first Green Line station needs to take this -9 offset add add it to the number of stations on the Green Line branch. This results in an xshift of -13 for West Valley Central, allowing it to align nicely with Murray Central.

Beyond this, note that at Library and Planetarium, in order to get some more space, we can use a different xshift value instead of adding a dummy station for spacing. This is because the branches are shorter than the longest branch (the Green Line) in this case.

Putting it all together

Now we'll add in the strokes to get our final map. We'll also adjust the angle of the station names using stnfontangle to make things fit (and to align text direction to the angled lines).

For this final map, we have also made some adjustments to the combined station (switching from a black circle to the colored variant utilized on the current official map as of Jan 2019) and have applied text/icon offsets as necessary.

Our strokes here are broken up with rather arbitrarily chosen start and end points, though that is a consequence of locknumstations.

In addition, note the usage of the station object's name field and how the text renders with multiple elements in the array. In this particular map, it has been used to ensure that labels don't extend onto other lines or out of the map itself. We have also adjusted the default lineheight to fit the entire map without expanding the size of the canvas itself.

The abridged source is below, as usual.

var obj_line3 = {
    "linename": "UTA TRAX Light Rail",
    "iconID": ["ICON_BLUE", "ICON_RED", "ICON_GREEN"],
    "locknumstations": 30,
    "lineheight": 288,
    "maincustomsvgbg": "<text x='16' y='460' fill='#AAAAAA' text-anchor='start' dominant-baseline='central'>01/2019</text>",
    "strokes": [
        {
            "color": "#0055A4",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": 160,
            "endlinkheight": 160,
            "endpoint": 12.75
        },
        {
            "color": "#0055A4",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": 160,
            "startpoint": 12.75,
            "endpoint": 15.75
        },
        {
            "color": "#0055A4",
            "strokewidth": "14px",
            "linecap": "round",
            "startpoint": 15.75,
            "endpoint": 40
        },
        {
            "color": "#0055A4",
            "strokewidth": "14px",
            "linecap": "round",
            "endlinkheight": -144,
            "startpoint": 40,
            "endpoint": 43
        },
        {
            "color": "#0055A4",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": -144,
            "endlinkheight": -144,
            "startpoint": 43,
            "endpoint": 46.5
        },
        {
            "color": "#EC1C24",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": 14,
            "endlinkheight": 14,
            "endpoint": 32.5
        },
        {
            "color": "#EC1C24",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": 14,
            "endlinkheight": 160,
            "startpoint": 32.5,
            "endpoint": 35.5
        },
        {
            "color": "#EC1C24",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": 160,
            "endlinkheight": 160,
            "startpoint": 35.5,
            "endpoint": 46.5
        },
        {
            "color": "#00A076",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": -144,
            "endlinkheight": -144,
            "startpoint": 18,
            "endpoint": 23.5
        },
        {
            "color": "#00A076",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": -144,
            "endlinkheight": -14,
            "startpoint": 23.5,
            "endpoint": 26.5
        },
        {
            "color": "#00A076",
            "strokewidth": "14px",
            "linecap": "round",
            "startlinkheight": -14,
            "endlinkheight": -14,
            "startpoint": 26.5
        }
    ],
    "stationtypes": [
        {
            "stypeID": "STATION_TYPE_BLUE",
            "stnnodes": [
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#0055A4"
                }
            ],
            "stnfontangle": 58
        },
        {
            "stypeID": "STATION_TYPE_RED",
            "stnnodes": [
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#EC1C24"
                }
            ],
            "stnfontangle": 58
        },
        {
            "stypeID": "STATION_TYPE_GREEN",
            "stnnodes": [
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#00A076"
                }
            ],
            "stnfontangle": 58
        },
        {
            "stypeID": "STATION_TYPE_NONE",
            "stnnodes": [
            ]
        },
        {
            "stypeID": "STATION_TYPE_BLUERED",
            "stnnodes": [
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#0055A4"
                },
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#EC1C24",
                    "dy": 14
                },
                {
                    "componenttype": "RECT",
                    "stationstrokewidth": 0,
                    "stationwidth": 10,
                    "stationheight": 14,
                    "scolor": "#FFFFFF",
                    "dy": 7
                }
            ],
            "stnfontangle": 58
        },
        {
            "stypeID": "STATION_TYPE_BLUEGREEN",
            "stnnodes": [
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#0055A4"
                },
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#00A076",
                    "dy": -14
                },
                {
                    "componenttype": "RECT",
                    "stationstrokewidth": 0,
                    "stationwidth": 10,
                    "stationheight": 14,
                    "scolor": "#FFFFFF",
                    "dy": -7
                }
            ],
            "stnfontangle": 58
        },
        {
            "stypeID": "STATION_TYPE_COMBINED",
            "stnnodes": [
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#0055A4"
                },
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#00A076",
                    "dy": -14
                },
                {
                    "stationradius": 7,
                    "stationstrokewidth": 4,
                    "fcolor": "white",
                    "scolor": "#EC1C24",
                    "dy": 14
                },
                {
                    "componenttype": "RECT",
                    "stationstrokewidth": 0,
                    "stationwidth": 10,
                    "stationheight": 28,
                    "scolor": "#FFFFFF"
                }
            ],
            "stnfontangle": 58
        }
    ],
    "stations": [
        {
            "name": ["Draper", "Town Center"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Kimballs Lane"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Crescent View"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Sandy", "Civic Center"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Sandy Expo"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Historic Sandy"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Midvale Center"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Midvale","Fort Union"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": [""],
            "stationtype": "STATION_TYPE_NONE",
            "icons": [
            ],
            "dy": 160
        },
        {
            "name": ["Daybreak Pkwy."],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["South Jordan Pkwy."],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["5600 W. Old Bingham Hwy."],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["4800 W. Old Bingham Hwy."],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["Jordan Valley"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["Sugar Factory Rd."],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["West Jordan City Center"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["Historic Gardner"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["Bingham Junction"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "xshift": -9,
            "dy": 14
        },
        {
            "name": ["Fashion Place", "West"],
            "stationtype": "STATION_TYPE_BLUERED",
            "icons": [
            ],
            "xshift": -9
        },
        {
            "name": ["Murray Central"],
            "stationtype": "STATION_TYPE_BLUERED",
            "icons": [
                ["ICON_FRONTRUNNER"]
            ],
            "xshift": -9,
            "iconoffset": 14
        },
        {
            "name": ["Murray North"],
            "stationtype": "STATION_TYPE_BLUERED",
            "icons": [
            ],
            "xshift": -9
        },
        {
            "name": ["Meadowbrook"],
            "stationtype": "STATION_TYPE_BLUERED",
            "icons": [
            ],
            "xshift": -9
        },
        {
            "name": ["Millcreek"],
            "stationtype": "STATION_TYPE_BLUERED",
            "icons": [
            ],
            "xshift": -9
        },
        {
            "name": ["West Valley", "Central"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "dy": -144,
            "xshift": -13
        },
        {
            "name": ["Decker Lake"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "dy": -144,
            "xshift": -13
        },
        {
            "name": ["Redwood Junction"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "dy": -144,
            "xshift": -13
        },
        {
            "name": ["River Trail"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "dy": -144,
            "xshift": -13
        },
        {
            "name": [""],
            "stationtype": "STATION_TYPE_NONE",
            "icons": [
            ],
            "xshift": -9
        },
        {
            "name": ["Central Pointe"],
            "stationtype": "STATION_TYPE_COMBINED",
            "icons": [
                ["ICON_SLINE"]
            ],
            "xshift": -13,
            "textoffset": 14,
            "iconoffset": 14
        },
        {
            "name": ["Ballpark"],
            "stationtype": "STATION_TYPE_COMBINED",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["900 South"],
            "stationtype": "STATION_TYPE_COMBINED",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["Courthouse"],
            "stationtype": "STATION_TYPE_COMBINED",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["Gallivan Plaza"],
            "stationtype": "STATION_TYPE_BLUEGREEN",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["City Center"],
            "stationtype": "STATION_TYPE_BLUEGREEN",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["Temple Square"],
            "stationtype": "STATION_TYPE_BLUEGREEN",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["Arena"],
            "stationtype": "STATION_TYPE_BLUEGREEN",
            "icons": [
            ],
            "xshift": -13,
            "textoffset": 14
        },
        {
            "name": ["Library"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": ["Trolley"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": ["900 East"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": ["Stadium"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": ["University", "South Campus"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": ["Fort Douglas"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": ["University", "Medical Center"],
            "stationtype": "STATION_TYPE_RED",
            "icons": [
            ],
            "dy": 160,
            "xshift": -16
        },
        {
            "name": [""],
            "stationtype": "STATION_TYPE_NONE",
            "icons": [
            ],
            "xshift": -20
        },
        {
            "name": ["Planetarium"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": -144,
            "xshift": -20
        },
        {
            "name": ["Old Greek Town"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
            ],
            "dy": -144,
            "xshift": -20
        },
        {
            "name": ["Salt Lake Central"],
            "stationtype": "STATION_TYPE_BLUE",
            "icons": [
                ["ICON_FRONTRUNNER"]
            ],
            "dy": -144,
            "xshift": -20
        },
        {
            "name": ["North Temple", "Bridge"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
                ["ICON_FRONTRUNNER"]
            ],
            "xshift": -23,
            "dy": -14
        },
        {
            "name": ["Jackson/", "Euclid"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "xshift": -23,
            "dy": -14
        },
        {
            "name": ["Fairpark"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "xshift": -23,
            "dy": -14
        },
        {
            "name": ["Power"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "xshift": -23,
            "dy": -14
        },
        {
            "name": ["1940 W. North Temple"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "xshift": -23,
            "dy": -14
        },
        {
            "name": ["Airport"],
            "stationtype": "STATION_TYPE_GREEN",
            "icons": [
            ],
            "xshift": -23,
            "dy": -14
        }
    ]
};