search envelope-o feed check
Home Unanswered Active Tags New Question
user comment-o

Floating event feature is not working

Asked by Anonymous
1 month ago.

Hi

The floating event feature seems no to work in my case. I don't see the arrows on the events. I set the property floatingEvents to true, although this is the default value anyway. I also checked the start and end dates and they are outside the current date range (viewport).

This is my scheduler configuration:

 schedulerConfig: any = {
    rowHeaderColumns: [
      { text: '', display: "name" },
      { text: '' }
    ],

    durationBarVisible: false,
    durationBarMode: "PercentComplete",
    heightSpec: 'Parent100Pct',
    hideBorderFor100PctHeight: true,
    locale: this.localeService.localeId,
    cellWidthSpec: 'Auto',
    crosshairType: 'Full',
    timeHeaders: [
      { 'groupBy': "Month", 'format': "MMMM yyyy" },
      { 'groupBy': 'Week' },
      { 'groupBy': 'Day', 'format': 'd' }
    ],
    scale: 'CellDuration',
    cellDuration: 720,
    // https://forums.daypilot.org/question/5571/how-to-change-the-displayed-end-date-of-selected-range
    //eventEndSpec: 'Date',
    showNonBusiness: true,
    businessWeekends: false,
    floatingEvents: true,
    eventHeight: 20,
    headerHeight: 20,
    rowMinHeight: 20,
    eventStackingLineHeight: 100,
    rowMarginBottom: 7,
    eventMovingStartEndEnabled: true,
    eventResizingStartEndEnabled: true,
    timeRangeSelectingStartEndEnabled: true,
    groupConcurrentEvents: false,
    allowEventOverlap: true,
    allowMultiRange: false,
    multiSelectRectangle: 'Free',
    rowHeaderHideIconEnabled: false,
    multiMoveVerticalMode: 'All',
    allowMultiMove: false,
    treeEnabled: false,

    contextMenuResource: new DayPilot.Menu({
      items: [
        { text: this.dialogTextService.getTranslation('TitJumpToTimesheet'), onClick: (args) => { this.navigateToTimeSheet(args.source.data.id); }, hidden: false },
      ],
      onShow: (args) => {
        const personResource = args.source.data as PersonResource;

        args.menu.items[0].hidden = !this.isActiveAndSubordinatedPerson(personResource);

        if (args.menu.items.all(i => i.hidden)) {
          // Cancels the menu activation
          args.preventDefault();
        }
      }
    }),

    /**
     * Events handling settings
     */
    timeRangeSelectedHandling: 'Hold',
    eventMoveHandling: 'Update',
    eventResizeHandling: 'Update',
    eventDeleteHandling: 'Disabled',
    eventClickHandling: 'Select',
    eventHoverHandling: 'Bubble',

    timeRangeRightClickHandling: "ContextMenu",

    /**
     * Events handler
     */

    onAfterRender: (args) => {
      this.busyIndicatorService.hide();
    },

    onBeforeTimeHeaderRender: (args) => {
      if (args.header.level === 1) {
        args.header.html = `${this.dialogTextService.getTranslation('TitWeek')} ${args.header.start.weekNumberISO().padStart(2, '0')}`;
      }

      let start = new Date(args.header.start.value);
      if (args.header.level === 2 && start.isSame(Date.today())) {
        args.header.areas = [
          { start: args.header.start, end: args.header.end, bottom: 0, height: 2, backColor: 'blue' }
        ];
      }
    },

    onBeforeRowHeaderRender: (args) => {
      const personResource = args.row.data as PersonResource;

      // Status icons
      args.row.columns[1].areas = [];

      const leftOffset = 20
      let left = 60;
      // Same position for top and bottom
      // see https://forums.daypilot.org/question/5577/how-to-center-vertically-active-areas
      const topBottom = 5;

      if (personResource.isIndirectlySubordinatedToolTipText) {
        args.row.columns[1].areas.push(
          {
            left: left,
            top: topBottom,
            bottom: topBottom,
            style: "display: flex; align-items: center;",
            width: 16,
            html: '<img src="assets/icons/subordinate.png" height="16" width="16">',
            toolTip: personResource.isIndirectlySubordinatedToolTipText
          });

        left = left - leftOffset;
      }

      if (personResource.personWillEnterToolTipText) {
        args.row.columns[1].areas.push(
          {
            left: left,
            top: topBottom,
            bottom: topBottom,
            style: "display: flex; align-items: center;",
            width: 16,
            html: '<img src="assets/icons/Enter.png" height="16" width="16">',
            toolTip: personResource.personWillEnterToolTipText
          });

        left = left - leftOffset;
      }

      if (personResource.personLeftCompanyToolTipText) {
        args.row.columns[1].areas.push(
          {
            left: left,
            top: topBottom,
            bottom: topBottom,
            style: "display: flex; align-items: center;",
            width: 16,
            html: '<img src="assets/icons/leave.png" height="16" width="16">',
            toolTip: personResource.personLeftCompanyToolTipText
          });

        left = left - leftOffset;
      }

      if (personResource.calculationStatusToolTipText) {
        args.row.columns[1].areas.push(
          {
            left: left,
            top: topBottom,
            bottom: topBottom,
            style: "display: flex; align-items: center;",
            width: 16,
            html: '<img src="assets/icons/Error.png" height="16" width="16">',
            toolTip: personResource.calculationStatusToolTipText
          });

        left = left - leftOffset;
      }

      if (personResource.ignoreWorkProfileChangesToolTipText) {
        args.row.columns[1].areas.push(
          {
            left: left,
            top: topBottom,
            bottom: topBottom,
            style: "display: flex; align-items: center;",
            width: 16,
            html: '<img src="assets/icons/favorites.png" height="16" width="16">',
            toolTip: personResource.ignoreWorkProfileChangesToolTipText
          });

        left = left - leftOffset;
      }
    },

    onBeforeCellRender: (args) => {
      this.setDaysColor(args);
    },

    onBeforeEventRender: (args) => {
      const items = new Array<DayPilot.MenuItemData>();
      const personId = args.data.resource;
      const from = new Date(args.data.start);

      if (args.data.tags.type == 'Comment') {
        args.data.borderColor = 'transparent';
        args.data.resizeDisabled = true;

        if (!args.data.isReadonly && from.isAfter(this.clientConfigurationService.blockedDate.toDate()) &&
          this.hasCommentCorrection(personId)) {
          args.data.contextMenu = new DayPilot.Menu({
            items: [
              {
                text: this.dialogTextService.getTranslation('TitEditComment'),
                onClick: (args) => { this.editComment(args); }
              },
              {
                text: this.dialogTextService.getTranslation('TitDeleteComment'),
                onClick: (args) => { this.deleteComment(args); }
              }
            ]
          });
        }

        return;
      }

      if (args.data.tags.type == 'Absence') {
        let dayIsLocked = from.isSameOrBefore(this.clientConfigurationService.blockedDate.toDate());

        const dailyAbsence = args.data.tags.absenceEntry as DailyAbsenceEntry;
        const personResource = this.personResources.find(p => p.id == args.data.resource);

        // background color
        if (dailyAbsence.requestId != 0) {
          args.data.backColor = `#${args.data.tags.timeType.color}7F`;
          args.data.areas = [
            { left: 0, right: 0, top: 0, bottom: 0, style: "background-image: linear-gradient(135deg, #808080de 10%, transparent 10%, transparent 50%, #808080de 50%, #808080de 60%, transparent 60%, transparent); background-size: 10px 10px;" }
          ];
        }
        else {
          args.data.backColor = dayIsLocked ? `#${args.data.tags.timeType.color}7F` : `#${args.data.tags.timeType.color}`;
        }

        if (!dayIsLocked) {
          // Jump to time sheet
          if (this.isActiveAndSubordinatedPerson(personResource)) {
            items.push({
              text: this.dialogTextService.getTranslation('TitJumpToTimesheet'),
              onClick: (args) => { this.navigateToTimeSheet(args.source.data.resource); }
            });
          }
        }
      }

      if (items.any()) {
        args.data.contextMenu = new DayPilot.Menu({
          items: items
        });
      }
    },

    onTimeRangeRightClick: (args) => {
      const from = new Date(args.start.value);
      if (from.isSameOrBefore(this.clientConfigurationService.blockedDate.toDate())) {
        args.preventDefault();
      }
    },

    onTimeRangeSelecting: (args) => {
      let person = this.personService.getById(args.resource);
      let day = new Date(args.anchor.value);

      if ((this.currentPerson && this.currentPerson.personId != person.personId) || !day.isSame(this.selectedDay)) {
        this.currentPerson = person;
        this.selectedDay = day;
        this.updateBalanceChart();
      }
    },
  };

Answer posted by Dan Letecky [DayPilot]
1 month ago.

I recommend using the browser devtools to check the DOM structure. If an event is partially hidden (outside of the current viewport), the Scheduler adds a special <div> element with "scheduler_default_event_float_inner" CSS class that is displayed on top of the event. The arrow is defined using ::after pseudoclass in the default CSS theme.

This way you can see if the floating <div> is present and how it is displayed. It may be hidden by some other element or the CSS may be overrridden.

Please note that the floating <div> is not applied when the event starts before startDate and the scrollbar is at position 0 (horizontally). In this case, the event will be marked with "scheduler_default_event_continueleft" CSS class.

See also:
https://doc.daypilot.org/scheduler/css-classes/

Comment posted by Dan Letecky [DayPilot]
1 month ago.

Also, it's important to remember that active areas with position defined using left/right (unlike start/end) are floating as well. For some event types, you have defined an active area covering the whole event (left: 0, right: 0, top: 0, bottom: 0) which will be displayed on top of the floating <div>.

Since version 2022.4.5448, you can also make an active area non-floating by adding "nonFloating: true" to its properties:
https://release.daypilot.org/changes/js/

Comment posted by Anonymous
1 month ago.

If I understand you correctly, the floating event feature works only in combination with the horizontal scrollbar?

In my case I don't have the horizontal scrollbar, because I'm setting the cellWidthSpec property to "Auto".

So, I want always to show the arrows (left und right) to indicate that an event starts before the startDate or/and ends after the endDate of the viewport. It shouldn't matter whether the the scrollbar is at position 0 or it's not used at all (as in my case)

Is there a way to do this?

Comment posted by Dan Letecky [DayPilot]
1 month ago.

> If I understand you correctly, the floating event feature works only in combination with the horizontal scrollbar?

Yes.

If you show the full timeline using cellWidthSpec: "Auto" the floating events feature never get activated.

As I mentioned, events that start before visibleStart() and/or end after visibleEnd() will be marked by special CSS classes ("scheduler_default_event_continueleft" and "scheduler_default_event_continueright").

You can use these classes to define the arrows but it might be easier to use active areas - something like this:

dp.onBeforeEventRender = args => {
    args.data.areas = [];
    if (new DayPilot.Date(args.data.start) < dp.visibleStart()) {
        args.data.areas.push({
            left: 0,
            top: 15,
            width: 0,
            height: 0,
            style: "border-color: transparent red transparent transparent;border-style:solid;border-width:5px;"
        })
    }
    if (new DayPilot.Date(args.data.end) > dp.visibleEnd()) {
        args.data.areas.push({
            right: 0,
            top: 15,
            width: 0,
            height: 0,
            style: "border-color: transparent transparent transparent red;border-style:solid;border-width:5px;"
        })
    }
};
New Reply
This reply is
Attachments:
or drop files here
Your name (optional):