How To Use jQuery To Implement A Date TimeLine Progress Bar

This example will use jQuery to implement a date timeline progress bar animation. When you click the timeline, it will go to the date-time that you clicked. If you click the Start button at the beginning of the date timeline progress bar, it will start the progress bar automatically. If you click the Back To Now button at the end of the progress bar, it will slide to the current date-time in the progress bar.

1. Use jQuery To Implement Date TimeLine Progress Bar Example Files.

There are 3 source files that need you to implement, index.html, css/index.css, and js/jquery.progressTime.js. The js/jquery.min.js is the jQuery library file.

./
├── css
│   └── index.css
├── index.html
└── js
    ├── jquery.min.js
    └── jquery.progressTime.js

1.1 index.html.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>How To Use jQuery To Implement A Date TimeLine Progress Bar</title>

<link rel="stylesheet" href="css/index.css">

</head>
<body>

<div id="progressTime"></div>

<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.progressTime.js"></script>
<script type="text/javascript">
var hourTimestamp = 3600 * 1000;
var dayTimestamp = hourTimestamp * 24;

$("#progressTime").ProgressTime({
    container: "progressTime",
    startTime: new Date(formatDate(new Date(new Date().getTime() - dayTimestamp * 5), "YYYY/MM/DD 00:00:00")),
    endTime: new Date(formatDate(new Date(), "YYYY/MM/DD 00:00:00")),
    currentTime: new Date(formatDate(new Date(new Date().getTime() - dayTimestamp * 4), "YYYY/MM/DD 12:00:00")),
    interval: 300,
    delay: 2000,
    callback: function (config) {
        console.log(config);
    },
    animateCallback: function (config) {

        // Suppose it takes two seconds to request data after the animation is finished.
        var timer = setTimeout(function () {
            progressTime.options.toPlay = true; // The progress bar will continue to play after two seconds.
            clearTimeout(timer);
        }, 0);
    }
});
</script>

</body>
</html>

1.2 js/jquery.progressTime.js.

$(function ($, window) {
    var hourTimestamp = 3600 * 1000; // One hour time in milliseconds.
    var dayTimestamp = hourTimestamp * 24; // One day time in milliseconds.

    window.formatDate = function (date, type) {
        if ((date.getTime || new Date(date).getTime()) && typeof type === "string") {
            date = type.replace(/YYYY|MM|DD|HH|hh|MM|mm|SS|ss/g, function ($) {
                switch ($) {
                    case "YYYY":
                        return date.getFullYear();
                    case "MM":
                        return date.getMonth() >= 9 ? date.getMonth() + 1 : "0" + (date.getMonth() + 1);
                    case "mm":
                        return date.getMonth() + 1;
                    case "DD":
                        return date.getDate() > 9 ? date.getDate() : "0" + date.getDate();
                    case "dd":
                        return date.getDate();
                    case "HH":
                        return date.getHours() > 9 ? date.getHours() : "0" + date.getHours();
                    case "hh":
                        return date.getHours();
                    case "MM":
                        return date.getMinutes() > 9 ? date.getMinutes() : "0" + date.getMinutes();
                    case "mm":
                        return date.getMinutes();
                    case "SS":
                        return date.getSeconds() > 9 ? date.getSeconds() : "0" + date.getSeconds();
                    case "ss":
                        return date.getSeconds();
                    default:
                        return $;
                }
            });
        }
        return date;
    }

    function ProgressTime(options) {
        this.options = {
            container: "container", // The container id value.
            startTime: new Date(formatDate(new Date(new Date().getTime() - dayTimestamp * 10), "YYYY/MM/DD 00:00:00")), // Start datetime.
            endTime: new Date(formatDate(new Date(), "YYYY/MM/DD 00:00:00")), // End datetime.
            currentTime: new Date(new Date().getTime() - dayTimestamp * 7), // Current datetime.
            delay: 2000, // Auto play animation time.                                            
            isNow: true, // Set to ture to display the 'Back To Now' button at the progress bar right side.
            toPlay: true, // Is rendering complete or not
            animateFinish: true, // Is the animation complete or not.
            hoursInterval: 3,
            formatterDate: function (timer) { // Customized date time format
                return formatDate(new Date(timer), "YYYY/MM/DD/");
            },
            animateCallback: function (config) { // Callback function when animation complete.

            },
            callback: function (config) { // Call back function when user single click the date timeline progress bar.

            }
        }
        this.options = $.extend(this.options, options);
        this.id = this.options.container;
        this.startTime = this.options.startTime;
        this.endTime = this.options.endTime;
        this.currentTime = this.options.currentTime;
        this.currentTimeTemp = null;
        this.timer = null;
        this.init();

    }
    ProgressTime.prototype.init = function () {
        this.createDom();
        this.bindEvent();
        this.resize();
        return this;
    }

    ProgressTime.prototype.createDom = function () {
        var left = $("<div class='" + this.id + "-left'></div>");
        var center = $("<div class='" + this.id + "-center'></div>");
        var isRight = this.options.isNow ? "" : "hide";
        var right = $("<div class='" + this.id + "-right " + isRight + "'></div>");

        var leftHtml = "<div class='" + this.id + "-left-t'></div><div class='" + this.id + "-left-b'><span class='" + this.id + "-left-b-start'></span></div>";
        left.append(leftHtml);

        var centerHtml = "<div class='" + this.id + "-center-t'><div class='" + this.id + "-center-t-bar'></div></div><div class='" + this.id + "-center-c'></div><div class='" + this.id + "-center-b'></div>";
        center.append(centerHtml);

        var rightHtml = "<div class='" + this.id + "-right-now'>Back To Now</div>";
        right.append(rightHtml);

        $("#" + this.id).append(left).append(center).append(right);

        this.createCenter(); // Create the content with DOM object.
    }
    ProgressTime.prototype.createCenter = function () {
        var cTop = $("." + this.id + "-center-t");

        var cCenter = $("." + this.id + "-center-c");
        var cbottom = $("." + this.id + "-center-b");

        cTop.append("<div class='" + this.id + "-center-t-tooltip'></div><div class='" + this.id + "-center-t-tooltipTemp hide'></div>");
        var days = (this.endTime.getTime() - this.startTime.getTime()) / dayTimestamp;


        var tempTime, cTopHtml = "",
            cCenterHtml = "",
            cBottomHtml = "",
            width = (cTop.width() / days) / cTop.width() * 100 + "%"; // Calculate the length of the time axis of each day, the percentage must be used, otherwise the calculation is not accurate.

        // Loop the days.
        for (var i = 0; i < days; i++) {
            var tempTime2 = new Date(this.startTime.getTime() + (i * dayTimestamp)); // Get current time.
            tempTime = this.options.formatterDate(tempTime2);
            cTopHtml += "<li style='width:" + width + ";'></li>";
            cCenterHtml += "<li class='" + this.id + "-center-c-ul-li' style='width:" + width + ";'></li>";
            cBottomHtml += "<li style='width:" + width + ";'>" + tempTime + "</li>";
        }
        cTop.append("<ul class='" + this.id + "-center-t-ul'>" + cTopHtml + "</ul>");
        cCenter.append("<ul class='" + this.id + "-center-c-ul'>" + cCenterHtml + "</ul>");
        cbottom.append("<ul class='" + this.id + "-center-b-ul'>" + cBottomHtml + "</ul>");

        // Calculate the progress bar x axis unit width for every three hours.
        var spanHtml = "";
        var liWidth = $("." + this.id + "-center-c-ul-li")[0].getBoundingClientRect().width; //
        var hoursWidth = liWidth / 24; // Calculate the width of each hour.
        var intervalCount = 24 / this.options.hoursInterval;
        for (var i = 1; i < intervalCount; i++) {
            var temp = (hoursWidth * i * this.options.hoursInterval) / liWidth * 100 + "%";
            spanHtml += "<span style='left:" + temp + ";'>" + (i * this.options.hoursInterval) + "</span>";
        }
        $("." + this.id + "-center-c-ul-li").append(spanHtml)

        this.setTime();
    }
    ProgressTime.prototype.setConfig = function (config) {
        var _this = this;
        var text = formatDate(new Date(config.time), "YYYY/MM/DD hh");

        var widthPercent = (config.width / $("." + this.id + "-center-t").width()) * 100 + "%"; // Use percentage to solve the adaptive problem at the end of time playing.
        // Flexible tooltip
        if (config.type === "mousemove") {
            $("." + this.id + "-center-t-tooltipTemp").removeClass("hide").text(text).css({
                "left": widthPercent
            });
            return;
        }

        // The length of the timeline.
        $("." + this.id + "-center-t-tooltip").text(text).stop().animate({
            "left": widthPercent
        });

        // Fixed tooltip.
        $("." + this.id + "-center-t-bar").stop().animate({
            width: widthPercent
        }, function () { // Animation complete. 
            _this.options.animateFinish = true;
            typeof _this.options.animateCallback === "function" && _this.options.animateCallback(config);
        });

        typeof this.options.callback === "function" && this.options.callback(config);
    }
    ProgressTime.prototype.setTime = function (e) {
        var layerX = e && e.originalEvent.layerX;
        var type = e && e.type;
        var hoursWidth = $("." + this.id + "-center-t-ul li")[0].getBoundingClientRect().width / 24; // Calculate the width of each hour.
        var tooltipTimestamp = this.currentTimeTemp || this.currentTime.getTime(); // Returns the timestamp of the current time.
        var num = Math.floor((tooltipTimestamp - this.startTime.getTime()) / hourTimestamp); // Calculate the total hours.
        num = layerX !== undefined ? Math.round(layerX / hoursWidth) : num;
        var progressWidth = num * hoursWidth; // Calculate the length of the timeline progress bar.

        if (layerX) { // Recalculate the distance when user move or click the timeline progress bar.
            tooltipTimestamp = Math.floor(this.startTime.getTime() + num * hourTimestamp);

            if (type === "click") {
                this.currentTimeTemp = tooltipTimestamp; // When click the timeline progress bar then save the current time.
            }
        }
        var time = formatDate(new Date(tooltipTimestamp), "YYYY/MM/DD hh:00:00");
        this.setConfig({
            time: time,
            width: progressWidth,
            type: type
        });
    }

    ProgressTime.prototype.bindEvent = function () {
        var _this = this;

        // Click event.
        $("." + this.id + "-center-t-ul").on("click", function (e) {
            _this.setTime(e);
        });

        // Move in / move out event.
        $("." + this.id + "-center-t-ul").on("mousemove", function (e) {
            _this.setTime(e);
        }).on("mouseleave", function () {
            $("." + _this.id + "-center-t-tooltipTemp").addClass("hide");
        });

        // Return back to the current time event.
        $("." + this.id + "-right-now").on("click", function () {
            _this.currentTimeTemp = _this.currentTime.getTime(); // Reset
            _this.setTime();
        });

        // Play the timeline progress bar.
        var flag = true;
        $("." + this.id + "-left-b-start").on("click", function () {
            var self = $(this);
            if (flag && _this.currentTimeTemp < _this.endTime) {
                _this.currentTimeTemp = _this.currentTimeTemp ? _this.currentTimeTemp : _this.currentTime.getTime(); // Add one hour milliseconds.
                flag = false;
                self.addClass("stop");
                if (!_this.timer) {
                    _this.timer = setInterval(function () {
                        if (_this.options.toPlay && _this.options.animateFinish) { // Called after the animation is completed and the page is rendered.
                            console.log("aaa");
                            _this.options.toPlay = false;
                            _this.options.animateFinish = false;
                            _this.currentTimeTemp += hourTimestamp;
                            if (_this.currentTimeTemp >= _this.endTime) { // Time boundary determination.
                                flag = true;
                                self.removeClass("stop");
                                clearInterval(_this.timer);
                                _this.timer = null;
                            }
                            _this.setTime();
                        }
                    }, _this.options.delay);
                }
            } else {
                flag = true;
                self.removeClass("stop");
                clearInterval(_this.timer);
                _this.timer = null;
            }
        });
    }

    ProgressTime.prototype.resize = function () { // Adaptive call only once to avoid web browser call reset method for multiple times.
        var _this = this;
        var tempTimer = null;
        $(window).resize(function () {
            if (!tempTimer && !_this.timer) { // Browser zooming will reset the timeline, so before reset we should check whether _this.timer exist or not.
                tempTimer = setTimeout(function () {
                    _this.setTime();
                    clearTimeout(tempTimer);
                    tempTimer = null;
                }, 0);
            }
        });
    }
    $.fn.extend({
        ProgressTime: function (options) {
            window.progressTime = new ProgressTime(options);
        }
    });
}(jQuery, window));

1.3 css/index.css.

* {
  margin: 0;
  padding: 0;
  list-style: none;
  text-decoration: none;
}

html,
body {
  height: 100%;
}
.hide{
    display: none;
}
#progressTime {
  height: 50px;
  width: 80%;
  border: 1px red solid;
  margin: 50px auto 0;
  display: flex;
  background-color: rgba(0, 0, 0, 0.7);
  min-width: 1024px;
}
.progressTime-left {
  width: 48px;
  height: 100%;
  display: flex;
  flex-direction: column;
}
.progressTime-left-t {
  height: 8px;
  background-color: #25d096;
  position: relative;
}
.progressTime-left-b {
  flex: 1;
  position: relative;
}
.progressTime-left-b-start {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0;
  height: 0;
  border: 6px solid;
  border-color: #fff #fff transparent transparent;
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  transform: rotate(45deg);
  margin-left: -9px;
  margin-top: -6px;
  cursor: pointer;
}
.progressTime-left-b-start.stop{
    width: 16px;
    height: 12px;
    border: none;
    -webkit-transform: rotate(0deg);
    -moz-transform: rotate(0deg);
    -o-transform: rotate(0deg);
    -ms-transform: rotate(0deg);
    transform: rotate(0deg);
    cursor: pointer;
}
.progressTime-left-b-start.stop::before{
    content: "";
    position: absolute;
    width: 4px;
    height: 12px;
    background-color: #FFF;
}
.progressTime-left-b-start.stop::after{
    content: "";
    position: absolute;
    width: 4px;
    height: 12px;
    background-color: #FFF;
    margin-left: 10px;
}
.progressTime-center {
  flex: 1;
  display: flex;
  flex-direction: column;
}
.progressTime-center-t {
  height: 8px;
  background-color: rgba(255, 255, 255, 0.7);
  box-sizing: border-box;
  cursor: pointer;
  position: relative;
}
.progressTime-center-t-bar {
  background-image: linear-gradient(
    to right,
    rgba(37, 208, 150, 1),
    rgba(45, 182, 205, 1)
  );
  height: 100%;
}
.progressTime-center-t-tooltip, .progressTime-center-t-tooltipTemp {
  position: absolute;
  padding: 0 8px;
  height: 24px;
  line-height: 24px;
  top: -35px;
  text-align: center;
  font-size: 14px;
  color: #fff;
  background-color: gray;
  border-radius: 3px;
  -webkit-transform: translateX(-50%);
  -o-transform: translateX(-50%);
  -moz-transform: translateX(-50%);
  -ms-transform: translateX(-50%);
  transform: translateX(-50%);
  min-width: 20px;
  white-space: nowrap;
}
.progressTime-center-t-tooltip::after, .progressTime-center-t-tooltipTemp::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -8px;
  border: 8px solid;
  border-color: gray transparent transparent transparent;
}
.progressTime-center-t-tooltipTemp{
    background-color: #ccc;
}
.progressTime-center-t-tooltipTemp::after{
    border-color: #ccc transparent transparent;
}
.progressTime-center-t-ul {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  z-index: 1;
}
.progressTime-center-t-ul::after {
  content: "";
  display: block;
  clear: both;
}
.progressTime-center-t-ul,
.progressTime-center-t-ul li {
  height: 100%;
}

.progressTime-center-t-ul li {
  float: left;
  border-left: 1px solid #999;
  box-sizing: border-box;
  height: 110%;
}

.progressTime-center-c {
  height: 12px;
  line-height: 12px;
}
.progressTime-center-c-ul::after {
  content: "";
  display: block;
  clear: both;
}
.progressTime-center-c-ul,
.progressTime-center-c-ul-li {
  height: 100%;
}
.progressTime-center-c-ul-li {
  float: left;
  border-left: 1px solid #999;
  border-bottom: 1px solid #999;
  box-sizing: border-box;
  position: relative;
}
.progressTime-center-c-ul-li span{
  position: absolute;
  color: #FFF;
  font-size: 12px;
  -webkit-transform: translateX(-50%) scale(.8);
  -moz-transform: translateX(-50%) scale(.8);
  -ms-transform: translateX(-50%) scale(.8);
  -o-transform: translateX(-50%) scale(.8);
  transform: translateX(-50%) scale(.8);
}
.progressTime-center-c-ul-li span::after{
  content: "";
  position: absolute;
  width: 1px;
  top: -90%;
  background-color: #FFF;
  height: 9px;
  -webkit-transform: translateX(-50%);
  -moz-transform: translateX(-50%);
  -ms-transform: translateX(-50%);
  -o-transform: translateX(-50%);
  transform: translateX(-50%);
  left: 50%;
}
.progressTime-center-b {
  flex: 1;
}
.progressTime-center-b-ul::after {
  content: "";
  display: block;
  clear: both;
}
.progressTime-center-b-ul,
.progressTime-center-b-ul li {
  height: 100%;
}
.progressTime-center-b-ul li {
  display: flex;
  justify-content: center;
  align-items: center;
  float: left;
  border-left: 1px solid #999;
  /* border-bottom: 1px solid #999; */
  color: #fff;
  font-size: 12px;
  box-sizing: border-box;
}
.progressTime-right {
  height: 100%;
  width: 120px;
  position: relative;
  border-left: 1px solid #999;
}
.progressTime-right-now {
  height: 28px;
  line-height: 28px;
  width: 80px;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  margin: auto;
  border-radius: 14px;
  background-color: #2db6cd;
  text-align: center;
  font-size: 12px;
  color: #fff;
  cursor: pointer;
}

Above is this example’s demo video.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.