JSFiddle - React, Tailwind, and code Playground

by Mike Jacobson

HTML

<div ng-app="myapp">
  <timeline></timeline>
</div>

CSS

.timeline-simple {
  font-size: 10px;
  height: 150px;
  overflow-x: scroll;
  white-space: nowrap;
}

.timeline-simple .timeline-bar {
  display: none;
  background-color: #ddd;
  bottom: 2px;
  height: 4px;
  position: relative;
  top: 100px;
  width: 100%;
}

.timeline-simple ol,
.el-cont {
  padding: 0 0 20px 20px;
  position: relative;
}

.timeline-simple ol li,
.el {
  border: 1px solid #ddd;
  border-bottom: none;
  border-right: none;
  display: block;
  height: 120px;
  list-style-type: none;
  position: absolute;
  white-space: normal;

}

.timeline-simple ol li > div,
.el-child {
  position: relative;
}
.timeline-simple-item {
  background-color: transparent;
  border: 1px solid #ddd;
  border-right-color: transparent;
  position: relative;
  height: 120px;
}

.timeline-simple-item-upper-left {
  border: 1px solid #ddd;
  border-top-color: #fff;
  border-left-color: #fff;
  margin-left: -1px;
  width: 67%;
  margin-top: -1px;
}

.timeline-simple-item-content {
  background-color: #fff;
  border: 1px solid #ddd;
  height: 50px;
  position: absolute;
  right: -60px;
  top: -1px;
  width: 80px;
}

.timeline-simple .fa-circle {
  font-size: 6px;
}

JavaScript

angular.module('myapp', [])
	.directive('timeline', timeline)

var data = [
	{ dueDateValue: 1470034800000, display: '08/01/2016' },
	{ dueDateValue: 1470034800000, display: '08/01/2016' },

	{ dueDateValue: 1479628800000, display: '11/20/2016' },
// 	{ dueDateValue: 1486195200000, display: '02/04/2017' },
// 	{ dueDateValue: 1492153200000, display: '04/14/2017' },
// 	{ dueDateValue: 1493881200000, display: '05/04/2017' },
// 	{ dueDateValue: 1505113200000, display: '09/11/2017' },
// 	{ dueDateValue: 1506322800000, display: '09/25/2017' },
// 	{ dueDateValue: 1506668400000, display: '09/29/2017' },
// 	{ dueDateValue: 1507014000000, display: '10/03/2017' },
// 	{ dueDateValue: 1507359600000, display: '10/07/2017' },
// 	{ dueDateValue: 1520755200000, display: '03/11/2018' },
 	{ dueDateValue: 1528700400000, display: '06/11/2018' }
];

if (data.length === 1) {
  data[0].offsetPercent = 0;
} else {
  var first = data[0].dueDateValue;
  var last = data[data.length - 1].dueDateValue;
  var range = last - first;
  console.log("range: ", range);
  var length = data.length;
  
  data.forEach(function(o, i) {
    o.offsetPercent = (((o.dueDateValue - first) / range) * 100);
    o.zIndex = (length - i) * 100;
  });
}

function TimelineCtrl($element, $timeout) {
  var ctrl = this;
  
  this.data = data;
  var MIN_UPPER_LEFT_WIDTH = 30;
  var MARKER_LINE_OFFSET = 20;
  var CONTENT_WIDTH = 80;
  
  $timeout(function() {
    //var $liList = $element[0].querySelectorAll('.el');
    var $liList = $element.find('li');
    console.log("$liList: ", $liList);
    var i, li, clientRect, prevLi, prevClientRect;
    var upperLeftWidth, contentWidth;
    var prevUpperLeftWidth;
    var liWidth = 170;
    var upperLeftHeight = 60;
    var MAX_UPPER_LEFT_HEIGHT = 90;
    for(i = 0; i < $liList.length; i++) {
      if (li) {
        prevLi = li;
        prevClientRect = clientRect;
        prevUpperLeftWidth = upperLeftWidth;
      }
      
      li = $liList[i];
      var upperLeftBox...