Arrange the array of tasks in the Gantt schedule by sorting them according to the combination of date and duration, while considering any static breaks that

i am working on an array that represents a gantt schedule. Each object in the array has specific properties

{
    id: string;
    startTime: Date;
    durationEstimated: number;
    isBreak: boolean;
}

and some generalized values. I have to iterate through the array and adjust startTime based on previous values, taking into account the "isBreak" property (which remains static - startTime/durationEstimated never changes)

For instance, if my array looks like this:

[ 
    {id: '1', startTime: "2020-04-01T08:30:00", durationEstimated: 60, isBreak: false},
    {id: '2', startTime: "2020-04-01T09:00:00", durationEstimated: 15, isBreak: true},
    {id: '3', startTime: "2020-04-01T09:45:00", durationEstimated: 60, isBreak: false},
    {id: '4', startTime: "2020-04-01T10:45:00", durationEstimated: 60, isBreak: false},
    {id: '5', startTime: "2020-04-01T11:45:00", durationEstimated: 60, isBreak: false},
    {id: '6', startTime: "2020-04-01T12:00:00", durationEstimated: 60, isBreak: true},
    {id: '7', startTime: "2020-04-01T13:45:00", durationEstimated: 60, isBreak: false}
] 

The first item(id='1') runs for 30 mins, followed by break(id='2') for 15 mins, then completes the last 30 mins before moving on to the next item(id='3'). (New items will always be added after position 0)

If I need to add another object (Starttime does not matter)

{id: '8', startTime: "2022-05-01T14:30:00", durationEstimated: 60, isBreak: false} 

Inserting this object at index 1 would result in the following array:

[ 
    {id: '1', startTime: "2020-04-01T09:30:00", durationEstimated: 60, isBreak: false}, 
    {id: '8', startTime: "2022-05-01T14:30:00", durationEstimated: 60, isBreak: false},
    {id: '2', startTime: "2020-04-01T09:00:00", durationEstimated: 15, isBreak: true}, 
    {id: '3', startTime: "2020-04-01T09:45:00", durationEstimated: 60, isBreak: false}, 
    {id: '4', startTime: "2020-04-01T10:45:00", durationEstimated: 60, isBreak: false},
    {id: '5', startTime: "2020-04-01T11:45:00", durationEstimated: 60, isBreak: false},
    {id: '6', startTime: "2020-04-01T12:00:00", durationEstimated: 60, isBreak: true},
    {id: '7', startTime: "2020-04-01T13:45:00", durationEstimated: 60, isBreak: false}
] 

This is where I start sorting and updating the startTime of all elements after the first one to accommodate breaks.

Expected output:

[ 
    {id: '1', startTime: "2020-04-01T08:30:00", durationEstimated: 60, isBreak: false}, 
    {id: '2', startTime: "2020-04-01T09:00:00", durationEstimated: 15, isBreak: true}, 
    {id: '8', startTime: "2020-04-01T09:45:00", durationEstimated: 60, isBreak: false},
    {id: '3', startTime: "2020-04-01T10:45:00", durationEstimated: 60, isBreak: false}, 
    {id: '4', startTime: "2020-04-01T11:45:00", durationEstimated: 60, isBreak: false},
    {id: '6', startTime: "2020-04-01T12:00:00", durationEstimated: 60, isBreak: true},
    {id: '5', startTime: "2020-04-01T13:45:00", durationEstimated: 60, isBreak: false},
    {id: '7', startTime: "2020-04-01T14:45:00", durationEstimated: 60, isBreak: false}
] 

The actual array consists of around 60-80 rows, with multiple breaks and different durationEstimated values.

Tried

I face challenges when rearranging items in the array to consider break times.

My approach involves iterating through the array, comparing each item against the previous item (startTime+duration), and adding the new date to the current item's startTime. The issue arises when dealing with breaks as they remain constant and do not change.

I have managed to handle this when only appending new items at the end of the array (since no sorting is required, just checking the previous value). However, in reality, new items can be inserted at any position.

Answer №1

While I don't have the exact JavaScript code conversion at hand, I do have a Python solution that seems to be functioning correctly.

import datetime, json

data = [ 
    {'id': '1', 'startTime': "2020-04-01T08:30:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '2', 'startTime': "2020-04-01T09:00:00", 'durationEstimated': 15, 'isBreak': True},
    {'id': '3', 'startTime': "2020-04-01T09:45:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '4', 'startTime': "2020-04-01T10:45:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '5', 'startTime': "2020-04-01T11:45:00", 'durationEstimated': 60, 'isBreak': False},
    {'id': '6', 'startTime': "2020-04-01T12:00:00", 'durationEstimated': 60, 'isBreak': True},
    {'id': '7', 'startTime': "2020-04-01T13:45:00", 'durationEstimated': 60, 'isBreak': False}
]

new_data = []

original_data_in_dict_form = {}
breaks = {}
sort_dict = {}
for item in data:
    start_date_obj = datetime.datetime.strptime(item['startTime'], "%Y-%m-%dT%H:%M:%S")

    if item['isBreak']:
        breaks[item['id']] = item
        breaks[item['id']]['endTime'] = start_date_obj + datetime.timedelta(minutes=item['durationEstimated'])
    else:
        original_data_in_dict_form[item['id']] = item
        original_data_in_dict_form[item['id']]['endTime'] = start_date_obj + datetime.timedelta(minutes=item['durationEstimated'])

for break_id in breaks:
    for original_id in original_data_in_dict_form:
        if breaks[break_id]['startTime'] > original_data_in_dict_form[original_id]['startTime'] and breaks[break_id]['endTime'] < original_data_in_dict_form[original_id]['endTime']:
            original_data_in_dict_form[original_id]['endTime'] += datetime.timedelta(minutes=breaks[break_id]['durationEstimated'])
        if original_id not in sort_dict:
            sort_dict[original_id] = original_data_in_dict_form[original_id]['endTime']

for original_id, end_time in sorted(sort_dict.items(), key=lambda p: p[1], reverse=False):
    new_data.append(original_data_in_dict_form[original_id])

print(new_data)

The sorting is based on endTime, but this can certainly be adjusted according to your needs. While the approach may not be the most efficient, it should serve as a good starting point for you.

Answer №2

I successfully implemented the solution provided by Torxed.

Initially, I iterated through each item in the list and established an endTime for each.

items = items.map(item => {
    item.startTime = new Date(item.startTime);
    const endTime = new Date(item.startTime);
    endTime.setMinutes(endTime.getMinutes() + item.durationEstimated);
    item.endTime = endTime;
    return item;
});

Then, I segregated the items into arrays based on whether they were "real" or "break" items.

const realItems = items.filter(x => !x.break);
const breakItems = items.filter(x => x.break);

Iterate over all realItems

Set the startTime using the previous values of endTime

Determine item endTime by adding item duration to startTime

realItems.forEach((realItem, index) => {
    if (index !== 0) {
        realItem.startTime = new Date(realItems[index - 1].endTime);
        const endTime = new Date(new Date(realItem.startTime));
        endTime.setMinutes(endTime.getMinutes() + realItem.durationEstimated);
        realItem.endTime = endTime;
    } else {
        realItem.startTime = new Date(realItem.startTime);
        const endTime = new Date(new Date(realItem.startTime));
        endTime.setMinutes(endTime.getMinutes() + realItem.durationEstimated);
        realItem.endTime = endTime;
    }
});

Next, I looped through breakItems and checked if the endTime of an item is greater than or equal to the startTime of the break. If so, I adjusted the startTime and endTime of subsequent items by the duration of the break.

for (const breakItem of breakItems) {
    const breakStart = new Date(breakItem.startTime).getTime();
    for (let x = 0; x < realItems.length; x++) {
        const realItem = realItems[x];
        const realEnd = new Date(realItem.endTime).getTime();

        if (realEnd >= breakStart + realItem.durationEstimated * 60000) {
            const items = realItems.slice(x, realItems.length);
            for (const item of items) {
                item.startTime = new Date(item.startTime);
                item.startTime.setMinutes(item.startTime.getMinutes() + breakItem.durationEstimated);
                item.startTime = item.startTime;
                item.endTime = new Date(item.endTime);
                item.endTime.setMinutes(item.endTime.getMinutes() + breakItem.durationEstimated);
                item.endTime = item.endTime;
            }
            break;
        }
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Do we really need TypeScript project references when transpiling with Babel in an Electron project using Webpack?

Currently, I am in the process of setting up my project configuration and have not encountered any errors so far. However, based on my understanding of the Typescript documentation... It appears that Project references are not essential when using babel-l ...

Confusion arises from the code for processing an Ajax redirect

I finally succeeded in incorporating an Ajax call into my code, but I'm a bit puzzled about how to redirect after the call is made. Below is an example of my script, developed using CodeIgniter: <script type="text/javascript"> function myFunc ...

Exploring ways to retrieve item metadata from a Stripe checkout session

When setting up a Checkout session, I dynamically create prices using the price_data and product_data properties. I include metadata for each item within the product_data.metadata property. However, after a successful payment is made, I retrieve the sessi ...

Loading SVGs on the fly with Vue3 and Vite

Currently, I am in the process of transitioning my Vue2/Webpack application to Vue3/Vite. Here's an example of what works in Vue2/Webpack: <div v-html="require('!!html-loader!../../assets/icons/' + this.icon + '.svg')" ...

The trustworthiness of the 'isConnected' attribute in DOM elements

domNode.isConnected is a helpful flag found in Chrome that indicates if the domNode is included in the document. Is this feature supported across all browsers? If not, what are some alternative options that are efficient and work well for other browsers? ...

Has Chrome's console disappeared?

After reinstalling Chrome and opening the dev tools with F12, I encountered an error with the following code: console.debug('test'); The error message displayed was Uncaught ReferenceError: console is not defined(…) This issue persisted acro ...

Facing a completely empty page after upgrading to vuejs 2.0

For me, upgrading my application to 2.0 has proven to be quite a challenge and I've spent hours trying to figure it out. In the past, I used vuejs within my application for certain functionalities, without treating it as a standalone vuejs application ...

Eliminate the hover effect from every element

Is there a method in CSS or Javascript that allows me to eliminate the hover effect on all elements? I am specifically looking for a solution that will disable the hover effect on mobile devices while keeping it intact on desktop. I attempted using pointer ...

Mastering the art of looping and implementing logic in JavaScript using Regular

Unsure if it is possible to achieve this using regex under JavaScript, but I found the concept interesting and decided to give it a try. I wanted to clean up some HTML code by removing most tags completely, simply dropping them like <H1><img>& ...

Display array C in descending order

My task involves creating functions to print an array and fill it with descending numbers. I successfully created the necessary functions, but encountered a problem. When I use my custom printArray() function, the output is unclear. I can't figure ou ...

Activate BootstrapValidator to dynamically enable or disable the submit button as you type

Is there a way to keep the submit button enabled while typing in BootstrapValidator? ...

Exporting Textures with Custom Offsets to GLTF from Three.js Scene

UPDATE: I was initially puzzled about exporting to obj and mtl formats, but then I stumbled upon the GLTFExporter.js in three.js which allowed me to successfully extract both the geometry and texture from my project. However, a new challenge arose with t ...

Resolve resources in Angular UI Router without triggering a page reload

Currently, I have implemented the following code to handle resource resolution when the main state is loaded. However, I am looking for a way to re-resolve the resource without having to reload the page. Reloading the page would negatively impact the user ...

Fade in/out overlay effect when clicking on a content block

I've hit a roadblock while trying to implement overlay fading in and out to cover a block created by some JavaScript code. Here is a link to the project. When you click on any of the continents, a series of blocks with country flags will appear. You& ...

Why won't my AngularJS checkbox stay checked?

In my application, I have the following code: <input type="checkbox" ng-checked="vm.eduToEdit.test" /> {{vm.eduToEdit.test}} <input type="checkbox" ng-model="vm.eduToEdit.test"> The value of vm.eduToEdit.test is displaying t ...

Tips for retrieving the response data from a POST request in Express/NodeJS?

As a newcomer to Node/Express, I am seeking assistance with a specific scenario. My goal is to develop a function that will trigger upon calling an API endpoint and retrieve a list of addresses from another operational API. While following some tutorial co ...

The directive code takes precedence over the controller code and is executed first

A custom directive has been implemented and is utilized as shown below: <div car-form car="car" on-submit="createCar(car)"></div> This directive is used on both the new and edit pages, each with its own controller. The EditCarController retri ...

AJAX causing issues with file upload functionality

I am currently utilizing AJAX in a file upload process, you can view it here. However, I am facing an issue where the value is not being passed from one page (upload.php) to another page (file_upload_submit.php). I am unsure of how to retrieve the file val ...

JavaScript: Eliminate a specific element and retrieve the modified array

Is there a way to remove only one instance of an item from an array, even if there are multiple duplicates of that item? For example: let array = ["abc", "def", "ghi", "def"]; const toRemove = "def"; I attempted to find the index and splice the array, but ...

Unexpected behavior in React-Native when filtering array objects

I am currently working on a react-native project where I am dealing with an array object that is being fetched from the backend. Here is a snippet of the Array. { "2010":[ { "id":1243, "eventName": ...