Premium support for our pure JavaScript UI components


Post by paul.manole »

Hello,

The application we are building is a planning application that uses Scheduler Pro. It has the concept of a planned and an actual view of the same events. For example: I can have a planned schedule for visits, but that does not mean that the visits happen at the planned date, so we record actual start date and end date for a visit once it has happened.

Our data model is simple, we have the same model with planned and actual dates on it that are initially equal, so they are never undefined. We map this model based on current view and feed it to the EventStore. In other words, depending on view mode, we map the planned or actual start dates to the startDate and endDate of the ModelConfig that is fed to the EventStore.data property. This is our mapping, not to be mistaken with the fields() static getter that the EventStore uses to do its own mapping.

The problem we see with this approach is that it is inefficient. We have to reload the same data just to change two fields, doing unnecessary malloc, project model has to rebuild, etc. As a side effect, we also can get React state to become out of sync with Scheduler if for example we store Scheduler data types in state, like selected events. If some events are selected and we feed new data to the EventStore, Scheduler keeps the previously selected events if possible, probably matched by ID. But then any previous event models we might have stored in React state are from a previous data load and now out of sync with Scheduler, and who knows what can happen if we try to use them, to call EvenModel APIs for example.

So, my question is, is there any other way to implement this kind of planned vs actual view switch on the same loaded data that is more efficient?

We thought of iterating over all events that we can get with getById and update their start and end dates but that is also very inefficient because of malloc of EventModels just to change two fields. Scheduler doesn't actually preallocate these objects I assume. Otherwise I can't imagine it being as fast and efficient as it is.

Another way we thought it might work is if we changed the static EventModel.fields getter to "flip" the dataSource of the startDate and endDate, assuming there is a way to let Scheduler know of this change and having it react to it.

Ultimately what we would hope for is a way to have Scheduler do the least amount of work in this scenario, which to us seems to be just a matter of updating the dataSource of a couple of fields and reflect that change in the DOM.

I might be wrong on many assumptions made here, so please forgive me and please let me know where I'm wrong and if there is a better way to implement what I've just described.

Thank you!


Post by alex.l »

Hi Paul,

Do you want to only display actual view data without any interaction, or you need 2 dataset fully interactive?
Because it might be implemented with renderers in case of 1 dataset is only for display.
Please see https://bryntum.com/products/gantt/docs/api/Gantt/feature/Baselines feature for Gantt. Is this something you're looking for in SchedulerPro?

All the best,
Alex


Post by paul.manole »

HI Alex,

Thanks for the reply. No, I need both to be fully interactive. We want to be able to interact with the events in either view mode (planned and actual).

For example, our event looks something like this:

type MyEvent = {
  startDate: Date, // required by Scheduler
  endDate: Date, // required by Scheduler
  // our own custom event properties, present on all events:
  plannedStartDate: Date,
  plannedEndDate: Date,
  actualStartDate: Date,
  actualEndDate: Date,
  // etc.
}

All we want is to be able to change what values startDate and endDate have, without recreating new objects and reloading the entire project model, and have Scheduler react to this switch by moving all events in their new locations on the time axis.

When we're in the planned view, we actually set the same values to startDate and endDate as plannedStartDate and plannedEndDate. Likewise for the actuals view.

Is there any way we can hook into Scheduler's rendering pipeline such that we can change where the event is rendered in time, and also have Scheduler react to ad-hoc requests to change where events are rendered on the time axis?

Something like function beforePositioningEvent({ event }): { startDate: Date, endDate?: Date, duration?: number, durationUnit?: string } {...}.

Or any kind of solution that would prevent a full EventStore.data = newData reload, because of its large overhead for Scheduler (depending on data size)?


Post by alex.l »

Hi,

In case you will switch data somewhere in a middle of positioning, what data should be used by ProjectModel for calculations?

All the best,
Alex


Post by alex.l »

Sorry for not giving you a solution right away, we need to understand a full picture before tell you if any way to do it better. Now I don't see better way than replace project model, it looks to me the only possible solution to have fully working and predictable behaviour.

All the best,
Alex


Post by paul.manole »

Thanks for the reply, Alex.

To reply to your question,

In case you will switch data somewhere in a middle of positioning, what data should be used by ProjectModel for calculations?

in this case, the project model should use the same start date and end date it uses normally. Now I realise that this shifting between actual and planned dates cannot happen just on the positioning of the events, as that means that the project model is already synchronized/built. The switch actually needs to happen before the model is built. So, maybe there is a solution where we can tell the model to rebuild using the same data that is already loaded in the stores, but to use different fields of the event model config for the final start and end date?

We also thought of this solution you propose:

Now I don't see better way than replace project model, it looks to me the only possible solution to have fully working and predictable behaviour.

But we didn't know if this could work.

Are you saying that we could create two project models, one for the actual view and one for the planned view, and then use the projectModel prop of the BryntumSchedulerPro React component to dynamically switch at runtime, between views? Does it support this correctly?

Even though I'm not sure we would want to go with this approach, because it would mean we would have to maintain two data sets for almost every operation. For example if we change the resource ID for an event, we would have to change it in both project models. But we'll see. It might ultimately come down to a tradeoff between memory and CPU.

OK, so, what do you suggest?


Post by arcady »

Hello,
Give that you want both states of the data to be "alive" I would go with switching projects so one dataset would represent a baseline and another the actual state of the project:

gantt.project = project1;
// switching to other project using different state
gantt.project = project2;

Yes that means doubling RAM consumption but that looks the easiest and cleanest way to me.
On the bright side it will allow to snapshot not only start/end dates but all the other factors (resource assignments, dependencies, constraints etc.).

And then you don't really need separate baseline start/end date fields ..so you can actually just load different states of the data to the same project:

gantt.project.inlineData = data1;
// switching to other project data state
gantt.project.inlineData = data2;

Best regards,
Arcady


Post by paul.manole »

Hi arcady,

I'll be extrapolating a bit here, since we don't directly use the Gantt component but I know it's one of the base classes/mixins of the component we actually use, SchedulerPro, more precisely BryntumSchedulerPro (the React wrapper).

So you're saying we could do it basically in 2 ways which satisfy the requirement to have both views "alive" and be available for fast switching back and forth between them (between planning vs actual dates views).

Those options would be:

1 - To create different project models, each with their own stores.

This means double the RAM (an understandable tradeoff, for which we get faster switching).

Or,

2 - Have the same project model, but create snapshots when switching and pass that snapshot as inlineData to the view that's being activated.

I assume there would be minimal overhead to this, as the model is already settled (flattened) and built (committed I think is the term).

This is an interesting idea because the only drawback I saw with 1. above is that we would have to keep the project models in sync when editing either one. For example, if we edit the start and end dates of an event in the planned view, business rules dictate that in certain conditions we also need to update the actual view with the same edit (but not always).

So, with 2., instead of caring about updating project model no 2, when modifying project model no 1, we could just worry about updating the active project model, and only when switching to the other project model, pass the snapshot of the previous project model to it.

I can only see this working if we have a way to tell each project model where to take the startDate and endDate values from.
The actual DTOs we attached to the runtime EventModels is basically the same, and contains both the planned and actual start and end dates, we just map them to startDate and endDate based on the currently active view.
And now the only way I know that we could tell Scheduler where to map from, is using the fields property on the custom model subclass, but we don't really want to create duplicate models for this.

I need to look into this snapshotting idea to get a better picture. Any suggestions where I should start?
And please correct me if my understanding above is wrong.

I'll be waiting for your feedback.

Thanks everyone for your help so far!


Post by mats »

@paul.manole Would you ever need to see both sets of dates at the same time? Or you are always looking at planned or actual? Never both sets visible at the same time?


Post by paul.manole »

mats wrote: Fri Nov 24, 2023 10:56 am

@paul.manole Would you ever need to see both sets of dates at the same time? Or you are always looking at planned or actual? Never both sets visible at the same time?

Never looking at both at the same time. We just need to switch between actual and planned at any time.

I'm assuming you're asking this because you want to know if we could reuse the same SchedulerPro instances?


Post Reply