• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

155
Views
Calendar date ordering: Occupation overview

I'm working on a calendar plugin that would show my occupation overview ordered as following:

Calendar with occupation overview

Now I've got the event on the calendar with moment.js, so they are formatted like this (sorted on Start date):

let events = [{
    name: 'Event A',
    start: '01-11-2021 00:00',
    end: '08-11-2021 00:00',
},{
    name: 'Event C',
    start: '03-11-2021 00:00',
    end: '06-11-2021 00:00',
},{
    name: 'Event E',
    start: '05-11-2021 00:00',
    end: '08-11-2021 00:00',
},{
    name: 'Event D',
    start: '07-11-2021 00:00',
    end: '12-11-2021 00:00',
},{
    name: 'Event B',
    start: '10-11-2021 00:00',
    end: '17-11-2021 00:00',
},]

Expected occupationOverview array would be something like:

let ooArray = [
{   // Longest/bottom bar
    start: '01-11-2021 00:00',
    end: '17-11-2021 00:00',
    group: 1
},
{   // Middle bar 1
    start: '03-11-2021 00:00',
    end: '08-11-2021 00:00',
    group: 2
},
{   // Middle bar 2
    start: '10-11-2021 00:00',
    end: '12-11-2021 00:00',
    group: 2
},
{   // Top bar 1
    start: '05-11-2021 00:00',
    end: '06-11-2021 00:00',
    group: 3
},
{   // Top bar 2
    start: '07-11-2021 00:00',
    end: '08-11-2021 00:00',
    group: 3
},]

I have honestly no clue how to group the calendar events so they give back an array with the start and end times as resulted in the red box.

Anybody that can help me figure this out? Thanks!

almost 3 years ago · Juan Pablo Isaza
3 answers
Answer question

0

Based on the updated question, sort all the dates keeping the attribute for start and end. Process them in order so that the first date (that must be a start) starts level 1, which is single booked.

If the next date is an end, that ends the bar. However, if the next date is a start, that increases the level (i.e. double booked). The following is an implementation, you might want to sort the bars by level or start date.

The function below firstly gets all the dates sorted in ascending order with their type - start or end. It then processes each date - start dates create a new bar, end dates end the most recent bar. When ended, the last bar is popped off starts and added to bars, which is an array of finished bars.

This depends on the source data being valid, i.e. it must start with a start and end with an end, they must be in the right order and of equal number.

One enhancement would be to ensure that where a start and end have the same date, the start is always sorted before the end so zero length events (milestones?) don't get ordered end-start, which would cause the level to be decremented before it's incremented. There may be other issues with starts and ends that have the same date and time, please test.

// Parse date in D-M-Y H:m format
function parseDMY(s) {
  let [D, M, Y, H, m] = s.split(/\D/);
  return new Date(Y, M - 1, D, H, m);
}

// Format as DD-MM-YYYY HH:mm
function formatDate(d) {
  let z = n => ('0'+n).slice(-2);
  return `${z(d.getDate())}-${z(d.getMonth()+1)}-${d.getFullYear()} ` +
         `${z(d.getHours())}:${z(d.getMinutes())}`;
}

// Generates "occupation" bars
function calcBookingLevels(events) {

  // Get sorted array of [{type, Date}]
  let dates = events.reduce( (dates, event) => {
    dates.push({type: 'start', date: parseDMY(event.start)},
               {type: 'end', date: parseDMY(event.end)});
    return dates;
  }, []).sort((a, b) => a.date - b.date);
  
  // Process dates to get occupation bars with levels
  let bars = [];
  let starts = [];
  let level = 0;
  dates.forEach(date => {

    // If it's a start, start a new bar
    if (date.type == 'start') {
      let bar = {level: ++level, start: formatDate(date.date)};
      starts.push(bar);

    // Otherwise it's an end, close the most recent bar and
    // move to bars array
    } else {
      let t = starts.pop();
      t.end = formatDate(date.date);
      --level;
      bars.push(t);
    }
  })
  
  return bars;
}

// Sample data
let events = [{
    name: 'Event A',
    start: '01-11-2021 00:00',
    end: '08-11-2021 00:00',
},{
    name: 'Event C',
    start: '03-11-2021 00:00',
    end: '06-11-2021 00:00',
},{
    name: 'Event E',
    start: '05-11-2021 00:00',
    end: '08-11-2021 00:00',
},{
    name: 'Event D',
    start: '07-11-2021 00:00',
    end: '12-11-2021 00:00',
},{
    name: 'Event B',
    start: '10-11-2021 00:00',
    end: '17-11-2021 00:00',
},];

// Run it...
console.log(calcBookingLevels(events));

If the dates were in YYYY-MM-DD HH:mm format then they could be sorted as strings without converting to Dates.

almost 3 years ago · Juan Pablo Isaza Report

0

Looks like you need to get the diff in milliseconds, and sort from greatest to least. You'll have to play with this to see which way it sorts (might need to flip the 'a' and 'b' on the diff statement, as I didn't run it against your array)

const sortedArray = array.sort((a, b) => a.diff(b))
almost 3 years ago · Juan Pablo Isaza Report

0

With the help of @RobG I figured it out. Here is my answer for interested people:

// Not needed for answer, but result gave warnings so yeah
moment.suppressDeprecationWarnings = true;

let newItems = []
let dateArray = []
let events = [{
    name: 'Event A',
    start: '01-11-2021 00:00',
    end: '08-11-2021 00:00',
},{
    name: 'Event C',
    start: '03-11-2021 00:00',
    end: '06-11-2021 00:00',
},{
    name: 'Event E',
    start: '05-11-2021 00:00',
    end: '08-11-2021 00:00',
},{
    name: 'Event D',
    start: '07-11-2021 00:00',
    end: '12-11-2021 00:00',
},{
    name: 'Event B',
    start: '10-11-2021 00:00',
    end: '17-11-2021 00:00',
},]

// Make one big array with all start and end dates
events.forEach(event=> {
   dateArray.push({
      type: 'start',
      date: event.start
   }, {
      type: 'end',
      date: event.end
   })
})


// Sort the dates from first to last
dateArray = dateArray.sort((left, right) => {
   return moment(left.date).diff(moment(right.date))
})


let groupID = -1

// Loop through the array with all dates and add them to a group 
// based on if the current date is a start or end
for (let i = 0; i < dateArray.length; i++) {
   if (dateArray[i].type === 'start') groupID++
   else groupID--

   for (let ii = 0; ii <= groupID; ii++) {
      if (dateArray[i + 1] && 
             !moment(dateArray[i].date).isSame(dateArray[i + 1].date)) {
         newItems.push({
            group: 1,
            start: dateArray[i].date,
            end: dateArray[i + 1].date,
            subgroup: 'sg_' + ii,
            subgroupOrder: ii
         })
      }
   }
}

console.log(newItems)
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

almost 3 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error