Premium support for our pure JavaScript UI components


Post by Shinya Umeshita »

We are trying to implement a feature which is similar to this example
https://bryntum.com/examples/scheduler-pro/resourcehistogram/

Requirements : When the event data in Scheduler Pro is modified . The Resource Histogram should dynamically change according to the new modifications(Provided with our logic). In the example this works perfectly when we change the data in scheduler pro , resource histogram automatically changes.

For this, one of our approaches was to Override the existing logic for resource histogram which changes with respect to events data , With our custom logic.

We have implemented the scheduler pro and resource histogram. (Used addPartner to display scheduler pro data). But we are unable to know why resource histogram is not dynamically changing when events data is changed in scheduler pro).

How can we get a result just like the one in example (Where resource histogram dynamically changes with respect to events data).

Can you give more information about this feature ?
(Like if need to use our custom logic which is dependent on events data how can we ovveride the existing logic).
(Is there any setting that we are missing which is needed to dynamically change the histogram with respect to changes in events)

Thank You


Post by alex.l »

Hi Shinya Umeshita,

Is there any setting that we are missing which is needed to dynamically change the histogram

We didn't see your implementation and we don't know what exactly did you overwrite, so we cannot say what are you missing.

ResourceHistogram is based on SchedulerProBase class and contains a complex logic inside.
Basically, histogram uses scheduler's project and updates the UI on any data change event in it.

All the best,
Alex


Post by Shinya Umeshita »

Thanks Alex, We were able to use dynamic resource allocation to resource histogram just like the one in the example.

But i would like to know if there is any way that we could customize this resource allocation . as per our needs we have a separate logic that we would like to implement.
so when events are changed it would trigger that logic and resource histogram will be changed accordingly.


Post by Shinya Umeshita »

this is the logic of current our implementation to create resource histogram event start end time

Attachments
rhlogic.png
rhlogic.png (29.87 KiB) Viewed 801 times

Post by arcady »

The allocation shown by the histogram is calculated by SchedulerProResourceMixin class calculateAllocation method.
Check its source code in Engine/quark/model/scheduler_pro/SchedulerProResourceMixin.ts file.
So you need to override that method to customize the allocation logic.


Post by kevin.snps »

Hi arcady,

We have overridden the calculateAllocation method, but get the error below when the schedulerPro loads on the page. Can you tell me what this error means, and how to fix it.

Uncaught (in promise) Error: Unknown identifier n-{"snps_um__DefaultResource__c":"a160l000003jSpEAAU"}.$.assigned
    at sp (schedulerpro.lwc.module.min.js:23)
    at Jf.addEdge (schedulerpro.lwc.module.min.js:23)
    at Jf.onReadIdentifier (schedulerpro.lwc.module.min.js:23)
    at Jf.calculateTransitionsStackGen (schedulerpro.lwc.module.min.js:23)
    at calculateTransitionsStackGen.next (<anonymous>)
    at Jf.calculateTransitions (schedulerpro.lwc.module.min.js:23)
    at calculateTransitions.next (<anonymous>)
    at Vm (schedulerpro.lwc.module.min.js:23)
    at eval (schedulerpro.lwc.module.min.js:23)

This is the method we have overridden. The attached file is the data used when the error came up.

export default (base) =>
  class ResourceAllocationInfo extends base.ResourceAllocationInfo {
    *calculateAllocation() {
      const result = [];
      const ticksCalendar = yield this.ticks;
      const resource = yield this.$.resource;
      // const includeInactiveEvents = yield this.$.includeInactiveEvents;
      console.log(resource);
      const assignments = yield resource.$.assigned;
      const assignmentsByCalendar = new Map();
      const eventRanges = [];

  for (const assignment of assignments) {
    if (!(yield* super.shouldIncludeAssignmentInAllocation(assignment))) {
      continue;
    }

    yield assignment.$.units;
    const event = yield assignment.$.event,
      startDate = yield event.$.startDate,
      endDate = yield event.$.endDate;
    eventRanges.push({
      startDate,
      endDate,
      assignment,
    });
    const eventCalendar = yield event.$.effectiveCalendar;
    let assigns = assignmentsByCalendar.get(eventCalendar);

    if (!assigns) {
      assigns = [];
      assignmentsByCalendar.set(eventCalendar, assigns);
    }

    assigns.push(assignment);
  }

  const eventRangesCalendar = new base.ResourceAllocationEventRangeCalendar(
    {
      intervals: eventRanges,
    },
  );
  const calendars = [
    ticksCalendar,
    eventRangesCalendar,
    ...assignmentsByCalendar.keys(),
  ];
  const ticksData = new Map();
  ticksCalendar.intervalStore.forEach((tick) => {
    const tickData = base.ResourceAllocationInterval.new({
      tick,
      resource,
    });
    ticksData.set(tick, tickData);
    result.push(tickData);
  });
  //let weightedUnitsSum, weightsSum;
  yield* resource.forEachAvailabilityInterval(
    {
      startDate: result[0].tick.startDate,
      endDate: result[result.length - 1].tick.endDate,
      calendars,
    },
    (intervalStartDate, intervalEndDate, intervalData) => {
      const isWorkingCalendar = intervalData.getCalendarsWorkStatus();

      if (isWorkingCalendar.get(ticksCalendar)) {
        const tick = intervalData.intervalsByCalendar.get(ticksCalendar)[0],
          intervalDuration =
            intervalEndDate.getTime() - intervalStartDate.getTime(),
          tickData = ticksData.get(tick);
        //   tickAssignments = tickData.assignments || new Set();

        // if (!tickData.assignments) {
        //  // weightedUnitsSum = 0;
        //   //weightsSum = 0;
        // }

        //let units = 0,
        // duration;
        intervalData.intervalsByCalendar
          .get(eventRangesCalendar)
          .forEach((interval) => {
            const assignment = interval.assignment;

            let effort;
            const manHour = assignment.event.manHour;
            // get the man hour for the event
            if (
              assignment &&
              isWorkingCalendar.get(assignment.event.effectiveCalendar)
            ) {
              if (
                Math.floor(
                  assignment.event.startDate.getTime() /
                    1000 /
                    60 /
                    60 /
                    24,
                ) !==
                Math.floor(
                  assignment.event.endDate.getTime() / 1000 / 60 / 60 / 24,
                )
              ) {
                // declare
                const businessHourStart = 9;
                const buisnessHourEnd = 17;
                const commonHours = buisnessHourEnd - businessHourStart;

                // calculate start work date
                const workingStartDate =
                  assignment.event.startDate.getHours();

                // calculate end work date
                const workingEndDate = assignment.event.endDate.getHours();

                // calculate first and last days available time
                const firstDayAvalableTime = Math.abs(
                  buisnessHourEnd - workingStartDate,
                );

                const lastDayAvalaibleTime = Math.abs(
                  workingEndDate - businessHourStart,
                );

                let totalWorkHours =
                  firstDayAvalableTime + lastDayAvalaibleTime;

                for (let i = 1; i < assignment.event.period - 1; i++) {
                  totalWorkHours += commonHours;
                }

                const startDate = intervalStartDate.getDate();

                if (startDate === assignment.event.startDate.getDate()) {
                  effort =
                    (firstDayAvalableTime / totalWorkHours) * manHour;
                } else if (
                  startDate === assignment.event.endDate.getDate()
                ) {
                  effort =
                    (lastDayAvalaibleTime / totalWorkHours) * manHour;
                } else {
                  effort = (commonHours / totalWorkHours) * manHour;
                }
              } else {
                effort = manHour;
              }

              tickData.effort += effort * 3600000;

              //units += assignment.units;
              //tickAssignments.add(assignment);
            }
          });
        tickData.maxEffort += intervalDuration;

        // if (units) {
        //   if (duration) {
        //     weightedUnitsSum += duration * units;
        //     weightsSum += duration;
        //     tickData.units = weightedUnitsSum / weightsSum;
        //   } else if (!weightedUnitsSum) {
        //     tickData.units = units;
        //   }
        // }

        // this code calculates if we need to extra work or not (red or green)

        // if (tickAssignments.size) {
        //   tickData.assignments = tickAssignments;
        //   tickData.isOverallocated =
        //     tickData.isOverallocated || units > 100;
        //   tickData.isUnderallocated =
        //     tickData.isUnderallocated || units < 100;
        // }
      }
    },
  );
  return result;
}
  };
Attachments
sample.json
(6.78 KiB) Downloaded 46 times

Post by arcady »

The method is not relevant if the Histogram is not displayed. Scheduler Pro view itself does not call it.
We need a runnable test case so we could reproduce the issue to assist you.

Your JSON looks strange BTW. Why do you have serialized Object in resource id field values?

"id": "{\"snps_um__DefaultResource__c\":\"a160l000003jSpIAAU\"}"

That snps_um__DefaultResource__c part looks repeating for each resource ..so a real identifier could probably be just a160l000003jSpIAAU string.


Post by kevin.snps »

I will attach a zip file of test case. Due to our company's policy, I cannot post my whole app for reproducing. Instead, I will post the whole section related to the resource histogram.

regarding

Your JSON looks strange BTW. Why do you have serialized Object in resource id field values?

columns of scheduler in our app isn't fixed, and because of that, the id is serialized. When I hard code this data, the resource histogram works as without error. But once I get the data from the server side, this error occurs. So, I am thinking that the serialization of id is not a problem.

Attachments
sandboxScheduler.zip
(8.2 KiB) Downloaded 44 times

Post by arcady »

The test case was not runnable since it threw some exceptions like The requested module './sandboxScheduler/data.js' does not provide an export named 'COLUMNS'... plus the project created there tried to load data by AJAX request while url was undefined.
I've fixed all the issues I met the way I guessed was correct (since I don't know your app details). But after fixing the issues it looked working fine and I didn't see any exceptions you mentioned.

Please provide a runnable test case that reproduces the issue or details on how we can reproduce it.


Post Reply