You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
Hey Rafał, I've had reports from a client of two similar issues so I've included them both in the same ticket here. When I refer to the top and bottom sections of the chart below, it is just to indicate that the top section has many items, while the bottom section is mostly empty.
Issue 1.
When many items (100+) are visible on the page at once, the chart stutters and becomes slow to the point of being unusable. This seems exacerbated when many of these items are within the same cell.
Replication steps
Scroll chart up and down over bottom section. Chart works fine; see chrome performance profile below.
Scroll chart up and down over top section Chart lags and stutters; see chrome performance profile below.
Note that the pointerMoveWrite function is now taking 550ms to complete instead of the 6-7ms it took in the previous image.
Looks like the primary cause of this is the recalculateRowHeight, fixOverLappedItems, and itemOverlapsWithOthers functions.
Issue 2.
Attempting to move items within the chart does not work when there are many items visible on the page.
Replication steps
Move item from bottom section to another slot. Item movement works as expected.
Try to move item from top section to another slot. Item follows cursor for the first few frames, but eventually disappears.
Code
Due to the large number of records I have moved the row and item data into separate files attached to this ticket. rows and items.zip
/* eslint-disable max-len */
/* eslint-disable no-bitwise */
/* eslint-disable import/extensions */
/* eslint-disable no-use-before-define */
/* eslint-disable no-case-declarations */
/* eslint-disable import/no-unresolved */
/* eslint-disable import/no-absolute-path */
/* globals
gstc
moment
ganttChartKey
*/
import GSTC from '/vendor/gantt-schedule-calendar-timeline/gstc.esm.min.js';
import { Plugin as Selection } from '/vendor/gantt-schedule-calendar-timeline/plugins/selection.esm.min.js';
import { Plugin as ItemMovement } from '/vendor/gantt-schedule-calendar-timeline/plugins/item-movement.esm.min.js';
import { Plugin as CalendarScroll } from '/vendor/gantt-schedule-calendar-timeline/plugins/calendar-scroll.esm.min.js';
import { Plugin as TimelinePointer } from '/vendor/gantt-schedule-calendar-timeline/plugins/timeline-pointer.esm.min.js';
let state;
let currentRowId;
let originalRowId;
let createdCopy;
const gstcApi = GSTC.api;
const getCorrectChartZoom = () => {
const scrollBar = 20;
const minimumWidth = 700;
const minimumZoom = 19.725;
const fullCalendar = $('#calendarContainer').width();
const crewColumn = $('.gstc__list-column-header-resizer').width() ?? 200;
const width = fullCalendar - crewColumn - scrollBar;
if (width < minimumWidth) {
return minimumZoom;
}
return -24.54442 + (63.90415 - (-24.54442)) / (1 + (width / 720.2646) ** 0.06526076);
};
const generateId = () => {
let result = '';
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (let i = 0; i < 5; i += 1) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
/**
* GSTC will die if it's supplied an item which
* specifies a row that doesn't exist...
* @param {Object} data Calendar state object
* @returns {Object} Safe calendar state object
*/
const cleanseData = (data) => {
const rows = Object.values(data.config.list.rows);
const items = Object.keys(data.config.chart.items);
for (const item of items) {
const { rowId } = data.config.chart.items[item];
if (!rows.find((row) => row.id === rowId)) {
delete data.config.chart.items[item];
}
}
return data;
};
const updateChartItem = (items) => {
if (!Array.isArray(items)) {
items = [items];
}
state.update('config.chart.items', (currentItems) => {
for (const item of items) {
if (item?.id) {
currentItems[item.id] = item;
}
}
return currentItems;
});
};
const onItemMoveEnd = async (items) => {
try {
updateChartItem(items.map((item) => ({
...item,
isLoading: true
})));
// API call to update item in db
} catch (error) {
console.error(error);
}
};
const onCopyClick = async ({ item }) => {
try {
const id = item?.id || gstcApi.GSTCID(generateId());
state.update('config.chart.items', (items) => {
items[id] = {
...item,
id
};
return items;
});
// API call to create item in db
} catch (error) {
console.error(error);
}
};
const initialiseCalendar = async () => {
try {
const gstcConfig = (to, from, rows, columns, items) => {
const movementConfig = {
shouldMuteNotNeededMethods: true,
enabled: true,
events: {
// eslint-disable-next-line no-unused-vars
onStart({ items: { before, targetData }, clickedItem }) {
currentRowId = targetData.rowId;
// eslint-disable-next-line no-undef
originalRowId = targetData.rowId;
// Old one keeps moving to the new cell, but then we create another one in the initial cell
createdCopy = GSTC.api.merge({}, targetData, { id: generateId() });
createdCopy.dependant = [];
createdCopy.linkedWith = [];
if (window.isCtrlDown) {
state.update('config.chart.items', (calItems) => {
calItems[createdCopy.id] = createdCopy;
return calItems;
});
}
return before;
},
onMove({ items: { before, after } }) {
if (currentRowId !== after[0].rowId) {
currentRowId = after[0].rowId;
}
return before.map((previousItemState, index) => {
const { isLoading } = previousItemState;
const hasLeave = previousItemState.userLeaveId;
const currentItemState = gstcApi.merge({}, after[index]);
const isAreaGroupRow = currentItemState.rowId.includes('areaGroup');
if (hasLeave || isAreaGroupRow) {
currentItemState.rowId = previousItemState.rowId;
}
if (isLoading) {
currentItemState.rowId = previousItemState.rowId;
currentItemState.time.end = previousItemState.time.end;
currentItemState.time.start = previousItemState.time.start;
}
return currentItemState;
});
},
onEnd({ items: { after, initial } }) {
let someItemHasChanged;
for (const [i, initialItem] of initial.entries()) {
const movedItem = after[i];
if (!movedItem) {
continue;
}
if (initialItem.rowId !== movedItem.rowId) {
someItemHasChanged = true;
break;
}
if (initialItem.time.start !== movedItem.time.start) {
someItemHasChanged = true;
break;
}
}
if (someItemHasChanged) {
/**
* For dev: When isCtrl is uncommented, probably need to await onItemMoveEnd before calling onCopyClick to avoid bugs with assigning users
*/
onItemMoveEnd(after);
if (window.isCtrlDown) {
const userId = createdCopy.rowId.includes('user') ? createdCopy.rowId.split('-')[2] : null;
onCopyClick({ item: createdCopy }, userId);
}
} else {
/**
* When users holds ctrl and drags elements it created new temp item in original cell.
* If item is returned into the same cell, we remove the temp item straight away for user experience.
* */
state.update('config.chart.items', (calItems) => {
delete calItems[createdCopy.id];
return calItems;
});
}
currentRowId = null;
return after;
}
}
};
const zoom = getCorrectChartZoom();
const plugins = [
CalendarScroll(),
TimelinePointer(),
Selection(),
ItemMovement(movementConfig)
];
return {
autoInnerHeight: true,
scroll: {
vertical: { precise: false, },
horizontal: { precise: false, },
},
chart: {
item: {
gap: {
top: 0,
bottom: 1,
},
height: 20,
},
time: {
to,
from,
zoom
},
items,
calendarLevels: [
[
{
zoomTo: 100,
period: 'month',
periodIncrement: 1,
format({ timeStart }) {
const weekIndex = moment(new Date(timeStart)).isoWeek();
return `${timeStart.format('MMMM')}, week ${weekIndex}`;
}
}
],
[{
main: true,
zoomTo: 100,
period: 'day',
periodIncrement: 1,
format({ timeStart }) {
// day.js format
return timeStart.format('dddd D');
}
}]
]
},
list: {
rows,
row: { height: 20 },
columns: { data: gstcApi.fromArray(columns) }
},
licenseKey: ganttChartKey.replace(/(\[)|(])|(")/gm, '').replace(/=/gm, '='),
plugins
};
};
// INSERT DATA FROM rows.js HERE
const rows = {};
// INSERT DATA FROM items.js HERE
const items = {};
const columns = [
{
width: 200,
id: 'user',
isHTML: true,
data: 'label',
expander: true,
header: { content: 'User' }
}
];
const to = 1731196800000;
const from = 1730642400000;
state = gstcApi.stateFromConfig(gstcConfig(to, from, rows, columns, items));
const element = $('#calendarContainer')[0];
element.addEventListener('gstc-loaded', () => {
gstc.api.scrollToTime(new Date());
$('#calendarContainer').css('opacity', '1');
state.update('config.plugin.Selection.cells', false);
});
state.data = cleanseData(state.data);
window.state = state;
window.gstc = GSTC({
state,
element
});
} catch (error) {
console.error(error);
}
};
initialiseCalendar();
gantt-schedule-timeline-calendar version
3.37.5
Screenshots or movies Issue 1.
Bottom section (works as expected)
Top section (major lag)
Issue 2.
Bottom section (works as expected)
Top section (item being moved disappears)
The text was updated successfully, but these errors were encountered:
Describe the bug
Hey Rafał, I've had reports from a client of two similar issues so I've included them both in the same ticket here. When I refer to the top and bottom sections of the chart below, it is just to indicate that the top section has many items, while the bottom section is mostly empty.
Issue 1.
When many items (100+) are visible on the page at once, the chart stutters and becomes slow to the point of being unusable. This seems exacerbated when many of these items are within the same cell.
Replication steps
Chart works fine; see chrome performance profile below.
Chart lags and stutters; see chrome performance profile below.
Note that the pointerMoveWrite function is now taking 550ms to complete instead of the 6-7ms it took in the previous image.
Looks like the primary cause of this is the recalculateRowHeight, fixOverLappedItems, and itemOverlapsWithOthers functions.
Issue 2.
Attempting to move items within the chart does not work when there are many items visible on the page.
Replication steps
Item movement works as expected.
Item follows cursor for the first few frames, but eventually disappears.
Code
Due to the large number of records I have moved the row and item data into separate files attached to this ticket.
rows and items.zip
gantt-schedule-timeline-calendar version
3.37.5
Screenshots or movies
Issue 1.
Bottom section (works as expected)
Top section (major lag)
Issue 2.
Bottom section (works as expected)
Top section (item being moved disappears)
The text was updated successfully, but these errors were encountered: