support icon indicating copy to clipboard operation
support copied to clipboard

Event bars stop selecting after move timeline using `pan` feature

Open chuckn0rris opened this issue 5 months ago • 0 comments

https://github.com/user-attachments/assets/9637dd85-137f-4060-acb7-bd6f4cee5303

Forum post

use this as a base : https://bryntum.com/products/scheduler/examples/bigdataset/

import { DateHelper, AsyncHelper, DataGenerator, Mask, Scheduler } from '../../build/scheduler.module.js?479836';
import shared from '../_shared/shared.module.js?479836';

// hide data generation
async function generateResources(
    resourceCount = resourceCountField.value,
    eventCount = eventCountField.value
) {
    const
        today                 = DateHelper.clearTime(new Date()),
        mask                  = Mask.mask('Generating records', scheduler.element),
        colors                = ['cyan', 'green', 'indigo'],
        resources             = [],
        events                = [],
        assignments           = [],
        dependencies          = [],
        resourceTimeRanges    = [],
        timeRanges            = [],
        useResourceTimeRanges = !scheduler.features.resourceTimeRanges.disabled,
        useTimeRanges         = !scheduler.features.timeRanges.disabled,
        useDependencies       = !scheduler.features.dependencies.disabled;

let schedulerEndDate = today,
    i, step;

console.time('generate');

const generator = DataGenerator.generate(resourceCount);

while ((step = generator.next()) && !step.done) {
    const res = step.value;

    resources.push(res);

    for (i = 0; i < eventCount; i++) {
        const
            startDate = DateHelper.add(today, Math.round(Math.random() * (i + 1) * 20), 'days'),
            duration  = Math.round(Math.random() * 9) + 2,
            endDate   = DateHelper.add(startDate, duration, 'days'),
            eventId   = events.length + 1;

        events.push({
            id         : eventId,
            name       : 'Task #' + (events.length + 1),
            startDate,
            duration,
            endDate,
            eventColor : colors[resources.length % 3]
        });

        assignments.push({
            id       : 'a' + eventId,
            event    : eventId,
            resource : res.id
        });

        if (useDependencies && i > 0) {
            dependencies.push({
                id   : dependencies.length + 1,
                from : eventId - 1,
                to   : eventId
            });
        }

        if (useResourceTimeRanges && i % 2 === 0) {
            resourceTimeRanges.push({
                id             : resourceTimeRanges.length + 1,
                resourceId     : res.id,
                name           : `Range ${resourceTimeRanges.length + 1}`,
                startDate      : DateHelper.add(startDate, Math.round(Math.random() * 5), 'days'),
                duration       : Math.round(Math.random() * 5) + 4,
                timeRangeColor : 'red'
            });
        }

        if (endDate > schedulerEndDate) {
            schedulerEndDate = endDate;
        }
    }

    if (resources.length % 2000 === 0) {
        mask.text = `Generated ${resources.length * eventCount} of ${resourceCount * eventCount} records`;

        await AsyncHelper.animationFrame();
    }
}

if (useTimeRanges) {
    let startDate = today;
    for (let i = 0; i < eventCount; i++) {

        startDate = DateHelper.add(startDate, Math.round(Math.random() * 8) + 15, 'days');

        timeRanges.push({
            id       : i + 1,
            name     : `Time range ${i + 1}`,
            startDate,
            duration : Math.round(Math.random() * 5) + 4
        });
    }
}

console.timeEnd('generate');

mask.text = 'Loading data';

// Give the UI a chance to catch up, to update the mask before proceeding
await AsyncHelper.sleep(100);

scheduler.suspendRefresh();
scheduler.endDate = schedulerEndDate;
scheduler.project = {
    assignmentStore : {
        // Boost record creation performance a bit, by not cloning the raw data object
        useRawData : true,
        data       : assignments
    },
    resourceStore : {
        useRawData : true,
        data       : resources
    },
    eventStore : {
        useRawData : true,
        data       : events
    },
    dependencyStore : {
        useRawData : true,
        data       : dependencies
    },
    resourceTimeRangeStore : {
        useRawData : true,
        data       : resourceTimeRanges
    },
    timeRangeStore : {
        useRawData : true,
        data       : timeRanges
    }
};
scheduler.resumeRefresh(true);
await scheduler.project.commitAsync();
mask.close();
}
// end-hide

function toggleCustom(show) {
    scheduler.widgetMap.featuresButton.hidden = resourceCountField.hidden  = eventCountField.hidden = !show;
}

function applyPreset(resources, events) {
    toggleCustom(false);

resourceCountField.value = resources;
eventCountField.value = events;

generateResources();
}

const scheduler = new Scheduler({
    appendTo                      : 'container',
    eventStyle                    : 'border',
    rowHeight                     : 50,
    // Turn off animations, to speed up the demo a bit since a lot will be on screen
    useInitialAnimation           : false,
    enableEventAnimations         : false,
    // Don't track timeline context while scrolling, speeds up scrolling a bit by hitting DOM less
    updateTimelineContextOnScroll : false,
    // Disabling sticky headers speeds up scrolling a bit, since `position: sticky` promotes element to its own layer
    stickyHeaders                 : false,

        useInitialAnimation: false,
        enableEventAnimations: false,
        multiEventSelect: true,
generateResources,

columns : [
    { type : 'rownumber' },
    { text : 'Id', field : 'id', width : 50, hidden : true },
    { text : 'First name', field : 'firstName', flex : 1 },
    { text : 'Surname', field : 'surName', flex : 1 },
    { text : 'Score', field : 'score', type : 'number', flex : 1 }
],

features : {
    // Features that can be toggled in Custom mode
    dependencies : {
        disabled : true
    },
    resourceTimeRanges : {
        disabled : true
    },
    timeRanges : {
        disabled       : true,
        enableResizing : true
    },
    eventNonWorkingTime : {
        disabled : true
    },
    nonWorkingTime : {
        disabled : true
    },
    // Turn off schedule tooltip to boost scrolling performance a bit
    scheduleTooltip : false,
    // Disabling sticky events speeds up scrolling a bit, since `position: sticky` promotes element to its own layer
    stickyEvents    : false,
             scheduleTooltip: false,
     stripe: true,
     // Turn the resource grid part of Scheduler into a tree
     tree: true,
     rowReorder: true, // Allow tree reoardering
     eventDragCreate: false,// Disable creation by drag on Gantt
     eventDragSelect: false,  //Incompatible with the EventDragSelect and Pan features. If either of those features are enabled, this feature has no effect.
     pan: true,
},

// hide toolbar settings
tbar : [
    'Presets',
    {
        type        : 'buttongroup',
        toggleGroup : true,
        items       : [
            {
                text       : '1K events',
                ref        : '1K',
                pressed    : true,
                dataConfig : {
                    resources : 200,
                    events    : 5
                }
            },
            {
                text       : '5K events',
                ref        : '5K',
                dataConfig : {
                    resources : 1000,
                    events    : 5
                }
            },
            {
                text       : '10K events',
                ref        : '10K',
                dataConfig : {
                    resources : 1000,
                    events    : 10
                }
            },
            {
                text : 'Custom',
                ref  : 'customButton',
                onClick() {
                    toggleCustom(true);
                }
            }
        ],
        onClick({ source : button }) {
            if (button.dataConfig) {
                applyPreset(button.dataConfig.resources, button.dataConfig.events);
            }
        }
    },
    '->',
    {
        ref                  : 'resourceCountField',
        type                 : 'number',
        placeholder          : 'Number of resources',
        label                : 'Resources',
        tooltip              : 'Enter number of resource rows to generate and press [ENTER]',
        min                  : 1,
        max                  : 10000,
        width                : 'auto',
        inputWidth           : '5em',
        keyStrokeChangeDelay : 500,
        changeOnSpin         : 500,
        hidden               : true,
        onChange             : ({ userAction }) => userAction && generateResources()
    },
    {
        ref                  : 'eventCountField',
        type                 : 'number',
        placeholder          : 'Number of events',
        label                : 'Events',
        tooltip              : 'Enter number of events per resource to generate and press [ENTER]',
        min                  : 1,
        max                  : 100,
        width                : 'auto',
        inputWidth           : '4em',
        keyStrokeChangeDelay : 500,
        changeOnSpin         : 500,
        hidden               : true,
        onChange             : ({ userAction }) => userAction && generateResources()
    },
    {
        type : 'button',
        ref  : 'featuresButton',
        text : 'Features',
        menu : [
            {
                text     : 'Dependencies',
                checked  : false,
                onToggle : ({ checked }) => {
                    scheduler.features.dependencies.disabled = !checked;

                    if (checked && !scheduler.dependencyStore.count) {
                        generateResources();
                    }
                }
            },
            {
                text     : 'Resource ranges',
                checked  : false,
                onToggle : ({ checked }) => {
                    scheduler.features.resourceTimeRanges.disabled = !checked;

                    if (checked && !scheduler.resourceTimeRangeStore.count) {
                        generateResources();
                    }
                }
            },
            {
                text     : 'Time ranges',
                checked  : false,
                onToggle : ({ checked }) => {
                    scheduler.features.timeRanges.disabled = !checked;

                    if (checked && !scheduler.timeRangeStore.count) {
                        generateResources();
                    }
                }
            },
            {
                text     : 'Non-working time',
                checked  : false,
                onToggle : ({ checked }) => {
                    scheduler.features.nonWorkingTime.disabled = !checked;
                }
            },
            {
                text     : 'Event non-working time',
                checked  : false,
                onToggle : ({ checked }) => {
                    scheduler.features.eventNonWorkingTime.disabled = !checked;
                }
            }
        ]
    },
    {
        type : 'viewpresetcombo'
    }
]
// end hide
});

const { resourceCountField, eventCountField } = scheduler.widgetMap;

applyPreset(200, 5);

CSS:

.b-sch-event-wrap.b-sch-style-border > .b-sch-event{
  opacity:1;
}


.b-sch-event.b-sch-event-selected, .b-sch-event.b-sch-event-selected .fa-solid {
    font-weight: 900 !important;
    z-index: 6;
}


.b-sch-event-selected {
    border-style: solid !important;
    border-width: medium !important;
    border-color: black !important;
    font-style: italic !important;
}

chuckn0rris avatar Sep 30 '24 08:09 chuckn0rris