bryntum / support

An issues-only repository for the Bryntum project management component suite which includes powerful Grid, Scheduler, Calendar, Kanban Task Board and Gantt chart components all built in pure JS / CSS / TypeScript
https://www.bryntum.com
53 stars 6 forks source link

Event buffer makes event nonworking time wrong calculation #9833

Closed NegativeDearc closed 3 days ago

NegativeDearc commented 1 month ago

scheduler pro version: 6.0.4

resource calendar feature and event buffer feature both activated.

With event buffer: image

No event buffer

image

event nonworking time should not out of the resource nonworking time limitation

matsbryntse commented 1 month ago

Thanks for reporting! Any chance you can share the data + config for this rendering?

NegativeDearc commented 4 weeks ago

Yes. @matsbryntse

Edit page: https://bryntum.com/products/schedulerpro/examples/travel-time/

eventNonWorkingTime : true and resourceNonWorkingTime: true

javascript

import { Toast, SchedulerPro, StringHelper, DateHelper } from '../../build/schedulerpro.module.js?478494';
import shared from '../_shared/shared.module.js?478494';

// IMPORTANT NOTICE: You are not allowed to use this access_token outside our demos, you are required to obtain your own
const leafletToken = 'pk.eyJ1IjoibWF0c2JyeW50c2UiLCJhIjoiY2tlcHdqd2lrM3hlZjJybHRpeDR0amo1cCJ9.PJc0GY_loGf0iQKlewuL0w';

const scheduler = new SchedulerPro({
    appendTo          : 'container',
    eventStyle        : 'colored',
    resourceImagePath : '../_shared/images/users/',
    features          : {
        eventNonWorkingTime : true,
        resourceNonWorkingTime : {
            enableMouseEvents: true,
            hideRangesOnZooming: false,
            maxTimeAxisUnit: 'month'
        },
        timeRanges : {
            showHeaderElements : false
        },
        dependencies : false,
        eventBuffer  : {
            tooltipTemplate : ({ duration }) => `<i class="b-icon b-fa-exchange"></i>Travel time: ${duration}`,
            renderer({ eventRecord, preambleConfig, postambleConfig }) {
                if (eventRecord.preamble) {
                    preambleConfig.icon = eventRecord.preambleIcon;
                    preambleConfig.cls  = eventRecord.preambleCls;
                    preambleConfig.text = eventRecord.preamble.toString(true) + (eventRecord.preambleText ? ` (${eventRecord.preambleText})` : '');
                }

                if (eventRecord.postamble) {
                    postambleConfig.icon = eventRecord.postambleIcon;
                    postambleConfig.cls  = eventRecord.postambleCls;
                    postambleConfig.text = eventRecord.postamble.toString(true) + (eventRecord.postambleText ? ` (${eventRecord.postambleText})` : '');
                }
            }
        },

        taskEdit : {
            items : {
                generalTab : {
                    items : {
                        percentDoneField : {
                            label : '% Done'
                        },
                        preambleField : {
                            label : 'Drive to'
                        },
                        postambleField : {
                            label : 'Drive back'
                        }
                    }
                }
            }
        },

        // The tooltip feature is customized to contain a LeafletJS map
        eventTooltip : {
            // Don't auto hide the tooltip when moving the mouse over it
            allowOver : true,

            // We initialize the map when the tooltip is shown
            onShow({ source : tooltip }) {
                const
                    { eventRecord } = tooltip,
                    { lat, lon }    = eventRecord?.address || {};

                if (tooltip.map) {
                    tooltip.map.remove();
                    // Calling `remove` on already removed instance will throw
                    tooltip.map = null;
                }

                if (lat && lon) {
                    const map = tooltip.map = window.L.map('eventmap', {
                        zoomControl : false,
                        zoom        : 13,
                        center      : [lat, lon]
                    });

                    window.L.tileLayer(`https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=${leafletToken}`, {
                        attribution : '&copy; <a target="_blank" href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>, <a target="_blank" href="https://www.mapbox.com/">Mapbox</a>',
                        id          : 'mapbox/streets-v11',
                        tileSize    : 512,
                        zoomOffset  : -1,
                        accessToken : leafletToken
                    }).addTo(map);

                    window.L.marker([lat, lon]).addTo(tooltip.map);
                }
            },
            // Define a custom HTML template with a map placeholder to show in the tooltip
            template : ({ eventRecord }) => {
                // Read from main event if this is a split part
                eventRecord = eventRecord.event || eventRecord;
                eventRecord.eventStyle = 'hollow'
                return `<header>
                     ${eventRecord.resource.get('image') ? `<img class="resource-image" src="../_shared/images/users/${eventRecord.resource.get('image')}.jpg"/>` : ''}
                    <div class="resource-info">
                        <span class="resource-name">${StringHelper.encodeHtml(eventRecord.resource.name)}</span>
                        <span class="resource-role">${StringHelper.encodeHtml(eventRecord.resource.role)}</span>
                    </div>
                </header>
                <div class="event-info">
                    <div class="event-details">
                        <strong><i class="b-icon b-fa-calendar"></i>${StringHelper.encodeHtml(eventRecord.name)}</strong>
                        ${DateHelper.format(eventRecord.startDate, 'LT')} - ${DateHelper.format(eventRecord.endDate, 'LT')}
                        <strong><i class="b-icon b-fa-map-marker"></i></i>Address</strong>
                        <span>${eventRecord.address?.name || ''}</span>
                        <strong><i class="b-icon b-fa-car-side"></i>Travel time</strong>
                        <span>${eventRecord.preamble || ''} <i class="b-icon b-fa-arrow-right"></i></span>
                        <span>${eventRecord.postamble || ''} <i class="b-icon b-fa-arrow-left"></i></span>
                    </div>
                    <div id="eventmap"></div>
                </div>
            `;
            }
        }
    },
    columns : [
        {
            text   : 'Projects',
            width  : 100,
            field  : 'category',
            hidden : true
        },
        {
            type     : 'resourceInfo',
            text     : 'Technicians',
            width    : 170,
            field    : 'name',
            showRole : false
        },
        {
            text   : 'Role',
            width  : 120,
            field  : 'role',
            editor : false
        },
        {
            text: 'calendar',
            type: 'resourceCalendar'
        }
    ],

    rowHeight : 80,
    barMargin : 10,
    startDate : new Date(2021, 10, 1, 6),
    endDate   : new Date(2021, 10, 1, 20),

    viewPreset : 'hourAndDay',

    project : {
        autoLoad   : true,
        eventStore : {
            fields : [
                // A few additional fields used to customize the travel time elements
                { name : 'preambleText' },
                { name : 'preambleIcon', defaultValue : 'b-fa b-fa-car' },
                { name : 'preambleCls' },
                { name : 'postambleText' },
                { name : 'postambleIcon', defaultValue : 'b-fa b-fa-car' },
                { name : 'postambleCls' },
                { name : 'durationUnit', defaultValue : 'h' }
            ]
        },
        transport : {
            load : {
                url : 'data/data.json'
            }
        },
        // This config enables response validation and dumping of found errors to the browser console.
        // It's meant to be used as a development stage helper only so please set it to false for production systems.
        validateResponse : true
    },

    eventRenderer({ eventRecord }) {
        const { name, fullDuration } = eventRecord;

        return {
            children : [
                {
                    className : 'event-name',
                    text      : name
                },
                {
                    className : 'event-duration',
                    text      : fullDuration
                }
            ]
        };
    },

    tbar : [
        {
            type    : 'slidetoggle',
            label   : 'Show travel time',
            ref     : 'travel-time-toggle-button', // For test purpose
            color   : 'b-blue',
            checked : true,
            onChange({ checked }) {
                scheduler.features.eventBuffer.disabled = !checked;
            }
        },
        {
            type    : 'slidetoggle',
            label   : 'Show duration label',
            ref     : 'duration-toggle-button', // For test purpose
            color   : 'b-blue',
            checked : true,
            onChange({ checked }) {
                scheduler.features.eventBuffer.showDuration = checked;
            }
        }
    ]
});

Toast.show({
    html : `
        <p>This demo uses the great <b>Leaflet</b> library (<a href="https://github.com/Leaflet/Leaflet">GitHub</a>,
        <a href="https://github.com/Leaflet/Leaflet/blob/main/LICENSE">BSD 2-Clause License</a>).</p>
        <p>It is a separately licensed 3rd party library not part of the Bryntum product,<br>if you plan to use it
        in your app you must use your own access token.</p>
    `,
    timeout : 10000
});
css

.b-sch-timerange, .b-sch-nonworkingtime{
  color:#999;
  font-size:1.1em;
  background:repeating-linear-gradient(-55deg, rgba(230, 50, 50, 0.7), rgba(230, 50, 50, 0.7) 5px, rgba(240, 50, 50, 0.4) 5px, rgba(240, 50, 50, 0.4) 10px);
}
.b-sch-resourcenonworkingtime {
  color:rgba(230, 50, 50);
  background:repeating-linear-gradient(-55deg, rgba(200, 200, 200, 0.3), rgba(200, 200, 200, 0.3) 10px, rgba(240, 240, 240, 0.3) 5px, rgba(240, 240, 240, 0.3) 20px);
}
.b-sch-resourcenonworkingtime i{
  margin:0.5em;
  font-size:1.2em;
  color:#eee;
  border:3px solid #ccc;
  border-radius:50%;
  height:2.5em;
  width:2.5em;
  display:flex;
  align-items:center;
  justify-content:center;
}
.b-sch-resourcenonworkingtime:hover{
  border-radius:5px;
  outline:2px solid rgba(230, 50, 50);
  outline-offset:-2px;
}

image

NegativeDearc commented 2 weeks ago

will this fix in next release? @matsbryntse. correct view is really import to users.

matsbryntse commented 2 weeks ago

It's fixed now, it'll be part of the next or the following release.