Search code examples
javascripthtmljquerycsstimeline

Horizontal hours slots


I'm trying to build horizontal hours slots viewer. So far I found what I need, but in months: https://codepen.io/rsschouwenaar/pen/vOodgO

This is the code:

<!doctype html>

<html lang="en">

<head>
    <meta charset="utf-8">

    <title>The HTML5 Herald</title>
    <meta name="description" content="The HTML5 Herald">
    <meta name="author" content="SitePoint">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="https://momentjs.com/downloads/moment.js"></script>

</head>

<body>

    <div id="timetable" class="clearfix">
        <div class="timetable_content">
            <ul class="months clearfix">
                <li data-month="8" data-year="2015">August</li>
                <li data-month="9" data-year="2015">September</li>
                <li data-month="10" data-year="2015">October</li>
                <li data-month="11" data-year="2015">November</li>
                <li data-month="12" data-year="2015">December</li>
                <li data-month="1" data-year="2016">January</li>
                <li data-month="2" data-year="2016">February</li>
                <li data-month="3" data-year="2016">March</li>
                <li data-month="4" data-year="2016">April</li>
                <li data-month="5" data-year="2016">May</li>
                <li data-month="6" data-year="2016">June</li>
                <li data-month="7" data-year="2016">July</li>
            </ul>
            <ul class="timeslots">
                <li>
                    <span class="timeslot" data-date-start="2015-8-10" data-date-end="2015-10-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-10-10" data-date-end="2016-2-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-12-10" data-date-end="2016-2-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-09-10" data-date-end="2016-7-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-1-10" data-date-end="2015-3-12">BDO</span>
                    <span class="button"></span>
                </li>
            </ul>
        </div>
    </div>
</body>
<style type="text/css">
#timetable {
     width: 100%;
     height: auto;
     max-width: 768px;
     overflow-y: hidden;
     border: 1px solid #ccc;
}
 #timetable ul {
     padding-left: 0;
     list-style: none;
     margin: 0 0 0 0;
}
 #timetable .timetable_content {
     width: 1024px;
}
 .months {
     max-height: 50px;
     overflow: hidden;
}
 .months li {
     width: 110px;
     text-align: center;
     float: left;
     display: inline-block;
     border-right: 1px solid #ccc;
     padding: 1em;
}
 .timeslots li {
     border-top: 1px solid #ccc;
     padding: 0.5em;
}
 .timeslots .timeslot {
     background: lightblue;
     padding: 0.5em;
     display: inline-block;
}
 .clearfix:after {
     content: "";
     display: table;
     clear: both;
}

</style>
<script>
    (function() {

        var firstMonthsLiElWidth = $('.months li:first').innerWidth() + 1;

        var monthItems = 0;
        $('.months li').each(function(index) {
            monthItems += firstMonthsLiElWidth;
        });

        $('.months, .timeslots, .timetable_content').width(monthItems);
        console.log('<================== start slots =============================>');
        $('.timeslots li').each(function(index) {

            var element = $(this).children('span.timeslot'),
                startDate = element.data().dateStart,
                endDate = element.data().dateEnd,
                startMonthAmountDaysInMonth = moment(startDate, "YYYY-MM-DD").daysInMonth(),
                endMonthAmountDaysInMonth = moment(endDate, "YYYY-MM-DD").daysInMonth();

            var startDateMoment = moment(startDate, 'YYYY-MM-DD');
            var endDateMoment = moment(endDate, 'YYYY-MM-DD');
            var daysInPorject = endDateMoment.diff(startDateMoment, 'days') // 1

            console.log('daysInPorject: ', daysInPorject);
            console.log('startMonthAmountDaysInMonth: ', startMonthAmountDaysInMonth);
            console.log('endMonthAmountDaysInMonth: ', endMonthAmountDaysInMonth);

            var startDateMonth = startDate.split("-")[1];
            var endDateMonth = endDate.split("-")[1];

            if (endDateMonth.indexOf('0') === 0) {
                endDateMonth = parseInt(endDateMonth, 10);
            }

            if (startDateMonth.indexOf('0') === 0) {
                startDateMonth = parseInt(startDateMonth, 10);
            }

            console.log('Months', startDateMonth + ' & ' + endDateMonth);

            var startDateEl = $(".months li[data-month='" + startDateMonth + "']").offset().left;
            var endDateEl = $(".months li[data-month='" + endDateMonth + "']").offset().left;
            var endDateElEnd = endDateEl + 110;
            var timeSlotWidth = endDateElEnd - startDateEl;
            var pixelsPerDay = (Math.round(firstMonthsLiElWidth / startMonthAmountDaysInMonth) * daysInPorject + 'px');

            console.log('Month start: ', startDateEl);
            console.log('pixelsPerDay: ', pixelsPerDay);
            console.log('Month end: ', endDateEl);
            console.log('Day end: ', endDateEl);
            console.log('Element length: ', timeSlotWidth);

            element.css('margin-left', startDateEl);
            element.width(pixelsPerDay);
            console.log('=============================');

        });

        console.log('Moment', moment("2012-02", "YYYY-MM").daysInMonth());

    })();
</script>

</html>

I have 2 problems with this example:

  1. I need it in pure JavaScript, not in jQuery.
  2. I need it in hours (all hours of the day), not in months.

This is what I did so far:

https://codepen.io/orassayag/pen/poeKVYq

This is my code:

<!doctype html>

<html lang="en">

<head>
    <meta charset="utf-8">

    <title>The HTML5 Herald</title>
    <meta name="description" content="The HTML5 Herald">
    <meta name="author" content="SitePoint">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="https://momentjs.com/downloads/moment.js"></script>

</head>

<body>

    <div id="timetable" class="clearfix">
        <div class="timetable_content">
            <ul class="hours clearfix">
                <li data-hour="00">00:00</li>
                <li data-hour="01">01:00</li>
                <li data-hour="02">02:00</li>
                <li data-hour="03">03:00</li>
                <li data-hour="04">04:00</li>
                <li data-hour="05">05:00</li>
                <li data-hour="06">06:00</li>
                <li data-hour="07">07:00</li>
                <li data-hour="08">08:00</li>
                <li data-hour="09">09:00</li>
                <li data-hour="10">10:00</li>
                <li data-hour="11">11:00</li>
                <li data-hour="12">12:00</li>
                <li data-hour="13">13:00</li>
                <li data-hour="14">14:00</li>
                <li data-hour="15">15:00</li>
                <li data-hour="16">16:00</li>
                <li data-hour="17">17:00</li>
                <li data-hour="18">18:00</li>
                <li data-hour="19">19:00</li>
                <li data-hour="20">20:00</li>
                <li data-hour="21">21:00</li>
                <li data-hour="22">22:00</li>
                <li data-hour="23">23:00</li>
                <li data-hour="00">00:00</li>
            </ul>
            <ul class="timeslots">
                <li>
                    <span class="timeslot" data-hour-start="18" data-hour-end="19">BDO</span>
                    <span class="button"></span>
                </li>
                <!--                 <li>
                    <span class="timeslot" data-date-start="2015-10-10" data-date-end="2016-2-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-12-10" data-date-end="2016-2-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-09-10" data-date-end="2016-7-12">BDO</span>
                    <span class="button"></span>
                </li>
                <li>
                    <span class="timeslot" data-date-start="2015-1-10" data-date-end="2015-3-12">BDO</span>
                    <span class="button"></span>
                </li> -->
            </ul>
        </div>
    </div>
</body>
<style type="text/css">
    #timetable {
        width: 100%;
        height: auto;
        max-width: 768px;
        overflow-y: hidden;
        border: 1px solid #ccc;
    }

    #timetable ul {
        padding-left: 0;
        list-style: none;
        margin: 0 0 0 0;
    }

    #timetable .timetable_content {
        width: 1024px;
    }

    .hours {
        max-height: 50px;
        overflow: hidden;
    }

    .hours li {
        width: 110px;
        text-align: center;
        float: left;
        display: inline-block;
        border-right: 1px solid #ccc;
        padding: 1em;
    }

    .timeslots li {
        border-top: 1px solid #ccc;
    }

    .timeslots .timeslot {
        background: lightblue;
        display: inline-block;
    }

    .clearfix:after {
        content: "";
        display: table;
        clear: both;
    }
</style>
<script>
    (function() {

        var firstHoursLiElWidth = $('.hours li:first').innerWidth();

        var hoursItems = 0;
        $('.hours li').each(function(index) {
            hoursItems += firstHoursLiElWidth;
        });

        $('.hours, .timeslots, .timetable_content').width(hoursItems);
        console.log('<================== start slots =============================>');
        $('.timeslots li').each(function(index) {

            var element = $(this).children('span.timeslot'),
                startDate = element.data().hourStart,
                endDate = element.data().hourEnd,
                startHourAmountHoursInDay = 24,
                endHourAmountHoursInDay = 24;

            var startDateMoment = startDate
            var endDateMoment = endDate
            var startDateHour = parseInt(startDateMoment, 10);
            var endDateHour = parseInt(endDateMoment, 10);
            var hoursInProject = (endDateHour - startDateHour) * 60;

            console.log('startDate: ', startDate);
            console.log('endDate: ', endDate);

            console.log('hoursInProject: ', hoursInProject);
            console.log('startMonthAmountDaysInMonth: ', startHourAmountHoursInDay);
            console.log('endMonthAmountDaysInMonth: ', endHourAmountHoursInDay);

            console.log('Hours', startDateHour + ' & ' + endDateHour);

            console.log('startDateHour: ' + startDateHour);
            console.log('endDateHour:' + endDateHour);
            var startDateEl = $(".hours li[data-hour='" + startDateHour + "']").offset().left - 10;
            var endDateEl = $(".hours li[data-hour='" + endDateHour + "']").offset().left;
            var endDateElEnd = endDateEl;
            var timeSlotWidth = endDateElEnd - startDateEl;
            var pixelsPerHour = (Math.round(firstHoursLiElWidth / startHourAmountHoursInDay) * hoursInProject + 'px');

            console.log('Month start: ', startDateEl);
            console.log('pixelsPerHour: ', pixelsPerHour);
            console.log('Month end: ', endDateEl);
            console.log('Day end: ', endDateEl);
            console.log('Element length: ', timeSlotWidth);

            element.css('margin-left', startDateEl);
            element.width(pixelsPerHour);
            console.log('=============================');

        });

    })();
</script>

</html>

So far I tried to convert it to hours, but I didn't manage to make it work, the hours don't match the slot, no matter what I do. Can someone help me? Thanks.


Solution

  • I am not sure on why you had a variable pixelsPerHour computed. The variable firstHoursLiElWidth should do the same work as per my understanding of your code. While setting the element.width you can simply multiply the firstHoursLiElWidth with the duration of your event in hours, which is computed in hoursInProject.

    I have updated your javascript. You can check below -

    NOTE- Please use meaningful and self explanatory variable names. I have removed unwanted variables and cleaned up the JS code. But please change the variable names.

    (function () {
      var firstHoursLiElWidth = $('.hours li:first').innerWidth();
      var hoursItems = 0;
      $('.hours li').each(function (index) {
        hoursItems += firstHoursLiElWidth;
      });
      $('.hours, .timeslots, .timetable_content').width(hoursItems);
      $('.timeslots li').each(function (index) {
        var element = $(this).children('span.timeslot'),
          startDate = element.data().hourStart,
          endDate = element.data().hourEnd;
        var hoursInProject = (endDate - startDate);
        var startDateEl = $(".hours li[data-hour='" + startDate + "']").offset().left - 10;
        element.css('margin-left', startDateEl);
        element.width(firstHoursLiElWidth * hoursInProject);
      });
    })();
        #timetable {
            width: 100%;
            height: auto;
            max-width: 768px;
            overflow-y: hidden;
            border: 1px solid #ccc;
        }
    
        #timetable ul {
            padding-left: 0;
            list-style: none;
            margin: 0 0 0 0;
        }
    
        #timetable .timetable_content {
            width: 1024px;
        }
    
        .hours {
            max-height: 50px;
            overflow: hidden;
        }
    
        .hours li {
            width: 110px;
            text-align: center;
            float: left;
            display: inline-block;
            border-right: 1px solid #ccc;
            padding: 1em;
        }
    
        .timeslots li {
            border-top: 1px solid #ccc;
        }
    
        .timeslots .timeslot {
            background: lightblue;
            display: inline-block;
        }
    
        .clearfix:after {
            content: "";
            display: table;
            clear: both;
        }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div id="timetable" class="clearfix">
        <div class="timetable_content">
          <ul class="hours clearfix">
            <li data-hour="00">00:00</li>
            <li data-hour="01">01:00</li>
            <li data-hour="02">02:00</li>
            <li data-hour="03">03:00</li>
            <li data-hour="04">04:00</li>
            <li data-hour="05">05:00</li>
            <li data-hour="06">06:00</li>
            <li data-hour="07">07:00</li>
            <li data-hour="08">08:00</li>
            <li data-hour="09">09:00</li>
            <li data-hour="10">10:00</li>
            <li data-hour="11">11:00</li>
            <li data-hour="12">12:00</li>
            <li data-hour="13">13:00</li>
            <li data-hour="14">14:00</li>
            <li data-hour="15">15:00</li>
            <li data-hour="16">16:00</li>
            <li data-hour="17">17:00</li>
            <li data-hour="18">18:00</li>
            <li data-hour="19">19:00</li>
            <li data-hour="20">20:00</li>
            <li data-hour="21">21:00</li>
            <li data-hour="22">22:00</li>
            <li data-hour="23">23:00</li>
            <li data-hour="00">00:00</li>
          </ul>
          <ul class="timeslots">
            <li>
              <span class="timeslot" data-hour-start="18" data-hour-end="19">BDO</span>
              <span class="button"></span>
            </li>
            <li>
              <span class="timeslot" data-hour-start="07" data-hour-end="10">BDO</span>
              <span class="button"></span>
            </li>
            <li>
              <span class="timeslot" data-hour-start="02" data-hour-end="04">BDO</span>
              <span class="button"></span>
            </li>
          </ul>
        </div>
      </div>