JSFiddle - React, Tailwind, and code Playground

by Marc Malignan

HTML

<div id='line1'></div>

CSS

.subline {
    height: 6px;
    margin: 200px 0 300px 20px;
    font-family: arial;
    white-space: nowrap;
}

.stop {
    position: relative;
    display: inline-block;
    height: 20px; width: 20px;
    top: -7px;
    margin-left: -10px;
    margin-right: 70px;
    background: inherit;
    border-radius: 50%;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
.stop:first-of-type , .stop:last-of-type {
    background: black;
}
.stop.connect {
    background: white;
    border: 2px solid black;
}

.rotate {
    position: absolute;
    top:-15px;
    -moz-transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
    -moz-transform-origin: top left;
    -webkit-transform-origin: top left;
}
.stop.connect .rotate {
    top:-17px; left:-2px;
}
.stop:first-of-type .rotate , .stop:last-of-type .rotate {
    top:-20px; left:-7px;
}
.stop:first-of-type.connect .rotate , .stop:last-of-type.connect .rotate {
    top:-22px; left:-9px;
}

.stop-name {
    line-height: 20px;
    font-size: 90%;
    font-weight: bold;
    color: steelblue;
    white-space: nowrap;
}
.stop:first-of-type .stop-name , .stop:last-of-type .stop-name {
    padding: 2px 5px;
    background: steelblue;
    color: white;
}

.stop-info {
    position: absolute;
    margin-left: 20px;
    padding: 2px 4px;
    line-height: 8px;
    font-size: 60%;
    color: white;
    background: peru;
    white-space: nowrap;
}
.stop:first-of-type .stop-info , .stop:last-of-type .stop-info {
    margin-top: 3px;
}

.connections {
    position: absolute;
    top:18px; left:7px;
    padding-top: 20px;
    border-left: 2px solid steelblue;
}

.connections-line {
    position: relative;
    margin-top: 10px;
    margin-left: 9px;
    min-height: 20px;
    width: 110px;
}
.connections-line:before {
    display: block;
    position: absolute;
    left: -20px;
    top: 2px;
    height: 20px; width: 20px;
    line-height: 16px;
    border-radius: 50%;
    background:...

JavaScript

var lines = [
    {
        id: 'm1',
        stops: [
            {
                name: 'La Défense',
                info: 'Grande Arche',
                connections: {
                    tram: [ 't2' ],
                    rer: [ 'rerA' ]
                }
            },
            { name: 'Esplanade de la Défense' },
            { name: 'Pont de Neuilly' },
            { 
                name: 'Les Sablons',
                info: 'Jardin d\'Acclimatation'
            },
            {
                name: 'Porte Maillot',
                connections: { rer: [ 'rerC' ] }
            },
            { name: 'Argentine' },
            {
                name: 'Charles de Gaulle - Etoile',
                connections: {
                    sub: [ 'm2', 'm6' ],
                    rer: [ 'rerA' ]
                }
            },
            { name: 'Georges V' },
            {
                name: 'Franklin D. Roosevelt',
                connections: { sub: [ 'm9' ] }
            },
            {
                name: 'Champs-Elysées - Clémenceau',
                connections: { sub: [ 'm13' ] }
            },
            {
                name: 'Concorde',
                connections: { sub: [ 'm8', 'm12' ] }
            },
            { name: 'Tuileries' },
            {
                name: 'Palais Royal - Musée du Louvre',
                connections: { sub: [ 'm7' ] }
            },
            { name: 'Louvre-Rivoli' },
            {
                name: 'Châtelet',
                connections: {
                    sub: [ 'm4', 'm7', 'm11', 'm14' ],
                    rer: [ 'rerA', 'rerB', 'rerD' ]
                }
            },
            {
                name: 'Hôtel de Ville',
                connections: { sub: [ 'm11' ] }
            },
            { 
                name: 'Saint-Paul',
                info: 'Le Marais'
            },
            {
                name: 'Bastille',
                connections: { sub: [ 'm5', 'm8' ] }
      ...