<div id="content" class="content">
  <div class="container-fluid timeline">
    <!-- ghost elements for background -->
    <div class="row background">
      <div class="col-lg-5 year-2018"></div>
      <div class="col-lg-7 year-2019"></div>
    </div>
    <!-- ghost elements for background: END -->
    
    <div class="container timeline__title">
      <h2 class="section-heading">ROAD MAP</h2>
    </div>
    <div class="container years">
      <div class="row">
        <div class="col-lg-5">2018</div>
        <div class="col-lg-7">2019</div>
      </div>
    </div>
    
    <div class="timeline__points">
      <div class="horizontal-line"></div>
      <div class="container">
        <div class="row">
          <div class="col-lg-5 year-2018">
            <!-- point -->
            <div class="point"
                 v-for="(point, index) in timeline2018">
              <div class="upper-content">
                <div class="tooltip tooltip--top"
                     :ref="'tooltip2018' + index"
                     v-if="index % 2 != 0">
                  <ul>
                    <li v-for="task in point.points"
                        v-text="task">
                    </li>
                  </ul>
                </div>
              </div>
              <div class="circle"
                   v-bind:class="{inThisQuarter: point.quarter == currentQuarter && year == 2018}"
                   v-text="point.quarter"
                   v-bind:ref="'circle2018' + index"
                   v-on:click="toggleTooltip(2018, index)">
              </div>
              <div class="bottom-content">
                <div class="tooltip tooltip--bottom"
                     v-bind:ref="'tooltip2018' + index"
                     v-if="index % 2 == 0">
                  <ul>
                    <li v-for="task in point.points"
                        v-text="task">
                    </li>
                  </ul>
                </div>
              </div>
            </div>
            <!-- point: END-->
          </div>
        
          <div class="col-lg-7 year-2019">
            <!-- point -->
            <div class="point"
                 v-for="(point, index) in timeline2019">
              <div class="upper-content">
                <div class="tooltip tooltip--top"
                     v-bind:ref="'tooltip2019' + index"
                     v-if="index % 2 != 0">
                  <ul>
                    <li v-for="task in point.points"
                        v-text="task">
                    </li>
                  </ul>
                </div>
              </div>
              <div class="circle"
                   v-bind:class="{inThisQuarter: point.quarter == currentQuarter && year == 2019}"
                   v-text="point.quarter"
                   v-bind:ref="'circle2019' + index"
                   v-on:click="toggleTooltip(2019, index)">
              </div>
              <div class="bottom-content">
                <div class="tooltip tooltip--bottom"
                     v-bind:ref="'tooltip2019' + index"
                     v-if="index % 2 == 0">
                  <ul>
                    <li v-for="task in point.points"
                        v-text="task">
                    </li>
                  </ul>
                </div>
              </div>
            </div>
            <!-- point: END-->
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
@import url(https://fonts.googleapis.com/css?family=Roboto);
@mixin flex($dir, $jus: flex-start, $ali: flex-start, $wrap: nowrap) {
  display: flex;
  flex-direction: $dir;
  justify-content: $jus;
  align-items: $ali;
  flex-wrap: $wrap;
}

$timeline-container-h: 640px;
$point-w: 120px;
$point-h: 300px;
$circle-size: 48px;
$primary-accent-dark: #7652D2;
$secondary-accent-dark: #9B75DE;
$easing: cubic-bezier(0.19, 1, 0.22, 1);

%pulsing-1 {
  animation: pulsing-1 2s $easing infinite alternate;
  @keyframes pulsing-1 {
    from {transform: scale(1);}
    to {transform: scale(1.7);}
  }
}
%pulsing-2 {
  animation: pulsing-2 2s $easing infinite alternate;
  @keyframes pulsing-2 {
    from {transform: scale(1);}
    to {transform: scale(2.1);}
  }
}
  
body {
  margin: 0;
  padding: 0;
  overflow-x: hidden;
  font-family: 'Roboto';
}

.section-heading {
  color: white;
  font-size: 48px;
  font-weight: 520;
}

.years {
  color: white;
  font-size: 36px;
  font-weight: 520;
}

.content {
  background: black;
  min-height: 100vh;
  @include flex(row, center, center);
}

.timeline {
  background: $primary-accent-dark;
  height: $timeline-container-h;
  padding: 36px 0;
  position: relative;
  margin: 128px 0;
  .background {
    width: 100%;
    height: inherit;
    position: absolute;
    top: 0;
    left: 1.1%;
    .year-2018 {
      background-color: $primary-accent-dark; 
    }
    .year-2019 {
      background-color: $secondary-accent-dark; 
    }
  }
  
  &__title, &__years, &__points {
    position: relative;
    z-index: 0;
  }
  
  &__points {
    // background: rgba(100, 100, 100, 0.5);
    height: $point-h;
    .year-2018, .year-2019 {
      @include flex(row, space-evenly);
    }
  }
  
  .horizontal-line {
    background: white;
    width: 100%;
    height: 4px;
    position: absolute;
    top: 50%;
  }
}

.point {
  width: $point-w;
  height: $point-h;
  @include flex(column, space-between, center);
  position: relative;
  z-index: 4;
  .upper-content {
    width: 100%;
    height: ($point-h * 0.5) - $circle-size;
    @include flex(column, flex-end);
    strong {
      color: white;
      font-size: 24px;
      margin-bottom: 24px;
    }
  }
  .bottom-content {
    width: 100%;
    // height: calc(#{$point-h} * 0.5 - #{$circle-size});
    height: ($point-h * 0.5) - $circle-size;
    @include flex(column, flex-start);
  }
}

.circle {
  background: orange;
  width: $circle-size;
  height: $circle-size;
  @include flex(row, center, center);
  border: 6px solid white;
  border-radius: 50%;
  color: white;
  font-weight: bold;
  box-shadow: 0 2px 2px 5px rgba(238, 145, 36, 0.2);
  &::before, &::after {
    content: '';
    display: inline-block;
    width: $circle-size;
    height: $circle-size;
    border: 4px solid transparent;
    border-radius: inherit;
    position: absolute;
    transition: all 0.5s ease-out;
    opacity: 0;
  }
  &::before {
    background: rgba(255, 255, 255, 0.25);
    z-index: -1;
  }
  &::after {
    background: rgba(255, 255, 255, 0.15);
    z-index: -2;
  }
  &.inThisQuarter {
    &::before {
      opacity: 1;
      @extend %pulsing-1;
    }
    &::after {
      opacity: 1;
      @extend %pulsing-2;
    }
  }
  &.active {  
    border-color: orange;
    &::before {
      animation: none;
    }
    &::after {
      animation: none;
      background-color: transparent;
      border-color: white;
      transform: scale(1.7);
      opacity: 1;
    }
  }
  &:hover {
    cursor: pointer;
  }
}

.tooltip {
  background-color: white;
  width: 300px;
  padding: 8px 4px;
  border-radius: 16px;
  transition: all 0.3s;
  opacity: 0;
  position: absolute;
  left: -74%;
  z-index: -3;
  &.active {
    opacity: 1;
  }
  &--top {
    margin-top: -10%;
    margin-bottom: 10%;
    &::before {
      content: '';
      display: inline-block;
      background: white;
      width: 5px;
      height: 24px;
      position: absolute;
      bottom: -24px;
      left: 49%;
    }
  }
  &--bottom {
    margin-top: 10%;
    &::before {
      content: '';
      display: inline-block;
      background: white;
      width: 5px;
      height: 24px;
      position: absolute;
      top: -24px;
      left: 49%;
    }
  }
}
View Compiled
var timeline2018 = [
  {
    quarter: 'Q3',
    points: [
      'Website launch',
      'Whitepaper release',
      'TOKOIN token distributions starts',
      'TOKOIN Wallet development'
    ]
  },
  {
    quarter: 'Q4',
    points: [
      'POC Launch on TestNet',
      'Onboard logistic partners on Tokoin ecosystem'
    ]
  }
];

var timeline2019 = [
  {
    quarter: 'Q1',
    points: [
      'Launch dApps on MainNet',
      'Onboard Warehousing partners on Tokoin ecosystem',
      'Onboard Financial partners on Tokoin ecosystem',
      'Expand local operation to 10 tier-one cities in Indonesia',
      'Onboard 50.000 users on Tokoin ecosystem'
    ]
  },
  {
    quarter: 'Q2',
    points: [
      'Launch Data Reputation engine',
      'Launch Data Visualization platform',
      'Launch Partner Suite platform'
    ]
  },
  {
    quarter: 'Q3',
    points: [
      'Launch TOKOIN POS system',
      'Launch Data Exchange platform for Token Stacking and Loyalty program',
      'Expand local operation to all capital cities in Indonesia',
      'Onboard 10.000 users for TOKOIN POS system'
    ]
  },
  {
    quarter: 'Q4',
    points: [
      'Expand hyper-local operation to Thailand,  Vietnam, Philippine, Malaysia and other potential emerging market'
    ]
  }
];

var date = new Date();
var month = date.getMonth();
var year = date.getFullYear();

var vm = new Vue({
  el: '#content',
  data: {
    timeline2018: timeline2018,
    timeline2019: timeline2019,
    month: month,
    year: year
  },
  computed: {
    currentQuarter: function() {
      if(this.month >= 0 && this.month <= 2) return 'Q1';
      else if(this.month >= 3 && this.month <= 5) return 'Q2';
      else if(this.month >= 6 && this.month <= 8) return 'Q3';
      return 'Q4';
    }
  },
  methods: {
    normalizeSelection(year, idx) {
      var circ, tooltip, yearTemp = 2018, j = 0;
      for(var i = 0; i < 6; i++) {
        if(i > 1) {
          yearTemp = 2019;
          j = 0;
        }
        
        if(j != idx) {
          circ = this.$refs['circle'+yearTemp+j][0];
          tooltip = this.$refs['tooltip'+yearTemp+j][0];
          circ.classList.remove('active');
          tooltip.classList.remove('active');
        }
        j++;
      }
    },
    
    toggleTooltip(year, idx) {
      var circ = this.$refs['circle'+year+idx][0];
      console.log(circ);
      var tooltip = this.$refs['tooltip'+year+idx][0];
      if(!circ.classList.contains('active')) {
        circ.classList.add('active');
        tooltip.classList.add('active');
      } else {
        circ.classList.remove('active');
        tooltip.classList.remove('active');
      }
    },
  }
});

External CSS

  1. https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.3.3/js/swiper.min.js