Our pure JavaScript Scheduler component


Post by peterjc »

Hi, I am looking at this [example][https://www.bryntum.com/examples/scheduler/configuration/].
screenshot9.png
screenshot9.png (19.74 KiB) Viewed 1132 times
I want to do exactly this, but just can't get it to work in my sample application (attached)

In the example above, I can see there is a eventRenderer and eventBodyTemplate (as below)
eventRenderer : ({ eventRecord }) => eventRecord.percentDone || 0,

    eventBodyTemplate : data => `<div class="value" style="width: ${data}%">${data || ''}</div>`
I have added these into my home.page.ts, and attached in home.page.html, and I set to 40 (instead of 0) if there is no setting for percentDone, however I just do not get the shading you in the example.

Any ideas what I could be missing here?

Thanks i advance for any help here
Attachments
scheduler-ionic1.zip
(215.64 KiB) Downloaded 73 times

Post by mats »

Try adding the 'percentDone' field to your own model ( we don't in the sample since all records have a value already in the date).

Docs:
https://bryntum.com/docs/scheduler/#Common/data/Model

Post by mats »

Updated sample code:
import '../_shared/shared.js'; // not required, our example styling etc.

import DateHelper from '../../lib/Common/helper/DateHelper.js';
import WidgetHelper from '../../lib/Common/helper/WidgetHelper.js';
import Store from '../../lib/Common/data/Store.js';
import '../../lib/Grid/feature/Stripe.js';

import EventModel from '../../lib/Scheduler/model/EventModel.js';
import Scheduler from '../../lib/Scheduler/view/Scheduler.js';
import PresetManager from '../../lib/Scheduler/preset/PresetManager.js';
import '../../lib/Scheduler/column/ResourceInfoColumn.js';

//region Presets & Widgets

PresetManager.registerPreset('dayNightShift', {
    tickWidth         : 35,
    rowHeight         : 32,
    displayDateFormat : 'HH:mm',
    shiftIncrement    : 1,
    shiftUnit         : 'day',
    timeResolution    : {
        unit      : 'minute',
        increment : 15
    },
    defaultSpan  : 24,
    headerConfig : {
        bottom : {
            unit       : 'hour',
            increment  : 1,
            dateFormat : 'H'
        },
        middle : {
            unit      : 'hour',
            increment : 12,
            renderer(startDate, endDate, headerConfig, cellIdx) {
                if (startDate.getHours() === 0) {
                    // Setting a custom CSS on the header cell element
                    headerConfig.headerCellCls = 'b-fa b-fa-moon';

                    return DateHelper.format(startDate, 'MMM DD') + ' Night Shift';
                }
                else {
                    // Setting a custom CSS on the header cell element
                    headerConfig.headerCellCls = 'b-fa b-fa-sun';

                    return DateHelper.format(startDate, 'MMM DD') + ' Day Shift';
                }
            }
        },
        top : {
            unit       : 'day',
            increment  : 1,
            dateFormat : 'MMMM Do YYYY'
        }
    }
});

const presets = new Store({
    idField : 'value',
    data    : [
        { name : 'Seconds', preset : 'secondAndMinute' },
        { name : 'Minutes', preset : 'minuteAndHour' },
        { name : 'Hours',   preset : 'hourAndDay' },
        { name : 'Days',    preset : 'weekAndDay' },
        { name : 'Day/night shift (custom)', preset : 'dayNightShift' },
        { name : 'Weeks',   preset : 'weekAndMonth' },
        { name : 'Weeks 2', preset : 'weekAndDayLetter' },
        { name : 'Weeks 3', preset : 'weekDateAndMonth' },
        { name : 'Months',  preset : 'monthAndYear' },
        { name : 'Years',   preset : 'year' },
        { name : 'Years 2', preset : 'manyYears' }
    ]
});

const [combo, zoomIn, zoomOut] = WidgetHelper.append([
    {
        type         : 'combo',
        width        : 200,
        ref          : 'preset',
        placeholder  : 'Preset',
        editable     : false,
        cls          : 'b-bright',
        store        : presets,
        valueField   : 'preset',
        displayField : 'name',
        value        : 'dayNightShift',
        picker       : {
            maxHeight : 500
        },
        onChange : ({ value }) => {
            // Prevents from zooming again when reacting to a zoomChange event
            if (!combo.skip) {
                scheduler.zoomTo(value);
            }
            combo.skip = false;
        }
    },
    {
        type    : 'button',
        ref     : 'zoomInButton',
        color   : 'b-blue b-raised',
        icon    : 'b-icon b-icon-search-plus',
        tooltip : 'Zoom in',
        onClick() {
            scheduler.zoomIn();
        }
    },
    {
        type    : 'button',
        ref     : 'zoomOutButton',
        color   : 'b-blue b-raised',
        icon    : 'b-icon b-icon-search-minus',
        tooltip : 'Zoom out',
        onClick() {
            scheduler.zoomOut();
        }
    }
], { insertFirst : document.getElementById('tools') || document.body });

//endregion

//region Data

let resources = [
        { 'id' : 1, 'name' : 'Arcady', 'role' : 'Core developer', eventColor : 'purple' },
        { 'id' : 2, 'name' : 'Dave', 'role' : 'Tech Sales', eventColor : 'indigo' },
        { 'id' : 3, 'name' : 'Henrik', 'role' : 'Sales', eventColor : 'blue' },
        { 'id' : 4, 'name' : 'Linda', 'role' : 'Core developer', eventColor : 'cyan' },
        { 'id' : 5, 'name' : 'Maxim', 'role' : 'Developer & UX', eventColor : 'green' },
        { 'id' : 6, 'name' : 'Mike', 'role' : 'CEO', eventColor : 'lime' },
        { 'id' : 7, 'name' : 'Lee', 'role' : 'CTO', eventColor : 'orange' }
    ],
    events    = [
        {
            resourceId  : 1,
            percentDone : 60,
            startDate   : new Date(2017, 0, 1, 10),
            endDate     : new Date(2017, 0, 1, 12)
        },
        {
            resourceId  : 2,
            percentDone : 20,
            startDate   : new Date(2017, 0, 1, 12),
            endDate     : new Date(2017, 0, 1, 17)
        },
        {
            resourceId  : 3,
            percentDone : 80,
            startDate   : new Date(2017, 0, 1, 14),
            endDate     : new Date(2017, 0, 1, 16)
        },
        {
            resourceId  : 4,
            percentDone : 90,
            startDate   : new Date(2017, 0, 1, 8),
            endDate     : new Date(2017, 0, 1, 11)
        },
        {
            resourceId  : 5,
            percentDone : 40,
            startDate   : new Date(2017, 0, 1, 15),
            endDate     : new Date(2017, 0, 1, 17)
        },
        {
            resourceId  : 6,
            percentDone : 70,
            startDate   : new Date(2017, 0, 1, 16),
            endDate     : new Date(2017, 0, 1, 18)
        }
    ];

//endregion

class EventModelWithPercent extends EventModel {
    static get fields() {
        return [
            { name : 'percentDone', type : 'number', defaultValue : 0 }
        ];
    }
}

const scheduler = new Scheduler({

    appendTo  : 'container',
    minHeight : '20em',

    features : {
        stripe : true,
        sort   : 'name'
    },

    columns : [
        {
            type      : 'resourceInfo',
            imagePath : '../_shared/images/users/',
            text      : 'Staff',
            width     : '10em'
        }
    ],

    resources : resources,
    eventStore : {
        modelClass : EventModelWithPercent,
        data : events
    },

    startDate  : new Date(2017, 0, 1),
    endDate    : new Date(2017, 0, 2),
    viewPreset : 'dayNightShift',

    eventRenderer : ({ eventRecord }) => eventRecord.percentDone || 0,

    eventBodyTemplate : data => `<div class="value" style="width: ${data}%">${data || ''}</div>`,

    listeners : {
        zoomChange({ level, levelConfig }) {
            // In case values are the same, combo change event won't be fired, so `skip` flag won't get reset.
            if (combo.value !== levelConfig.preset) {
                // Prevent combo from retriggering zoom
                combo.skip = true;
                combo.value = levelConfig.preset;
            }

            // To disable buttons based on zoom levels use this code:
            // zoomOut.disabled = level <= 0;
            // zoomIn.disabled = level >= this.zoomLevels.length - 1;

            // To disable buttons based on presets in combo use this code:
            const index = combo.store.indexOf(combo.record);
            zoomIn.disabled = index === 0;
            zoomOut.disabled = index === combo.store.count - 1;
        }
    }
});

Post by peterjc »

Thanks for that.

Also, in my case I could see I was missing the styles. The the examples app, I can see the shading comes from the background-color property, the width is set by the percentage (from the model), and finally the parent item need padding removed as done in the example...
screenshot11.png
screenshot11.png (153.94 KiB) Viewed 1113 times
.b-sch-event {
  border-radius: 3px;
  padding: 0;  <-----------
}
I Just manually set all this in my eventBodyTemplate to see that it is picked up....
public eventBodyTemplate = data => `<div class="value" style="width: 30%;height:100%;background-color:rgba(0, 0, 0, 0.1);margin:0;padding:0">banana</div>`
My mission now is to learn about the styles, eg I notice in all my own examples I have some things missing...

eg the sort arrow..
screenshot12.png
screenshot12.png (10.8 KiB) Viewed 1113 times
But this is a separate issue, I will now look into (I had some problems even including the default css via the Angular way, so currently manually linking)

Anyway, as far as this question, I have it all now.

Thankyou for your help!

Post by pmiklashevich »

Hello @peterjc,

Thanks for your feedback. Indeed, having css adjusted is required for this feature. Glad you figured it out.

About missing sort icon, our icons are based on font awesome. So it looks like FontAwesome font is missing on your page. Please include it and see if it works.

Best,
Pavel

Pavlo Miklashevych
Sr. Frontend Developer


Post by peterjc »

Hi, I fixed this missing font by including the following in my angular.json...
screenshot27.png
screenshot27.png (20.46 KiB) Viewed 1093 times
And now all works fine.

Thanks for that

Post Reply