Problem with dividing timeline fullcalendar in equal parts (custom timeline view) - javascript

I am trying to make a fullcalendar component which can divide a day in equal parts.
This is working for certain amounts (10, 20, ...)
But when working with a uneven amount (like 15). This does not work.
I made a code pen of a simplified version of the problem:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
timeZone: 'UTC',
headerToolbar: {
left: 'today prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineTenDay,resourceTimelineMonth,resourceTimelineYear'
},
initialView: 'resourceTimelineDay',
scrollTime: '08:00',
aspectRatio: 1.5,
views: {
resourceTimelineDay: {
duration: { days: 21 }, // Or whatever value you want.
slotDuration: "3:00:00",
slotLabelInterval: "21:00:00",
slotMaxTime: "24:00:00",
slotWidth: "8",
minTime: '00:00',
maxTime: "24:00:00",
},
resourceTimelineTenDay: {
type: 'resourceTimeline',
duration: { days: 10 },
buttonText: '10 days'
}
},
editable: true,
resourceAreaHeaderContent: 'Rooms',
resources: 'https://fullcalendar.io/demo-resources.json?with-nesting&with-colors',
events: 'https://fullcalendar.io/demo-events.json?single-day&for-resource-timeline'
});
calendar.render();
});
html, body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
#calendar {
max-width: 1100px;
margin: 40px auto;
}
<link href="https://cdn.jsdelivr.net/npm/fullcalendar-scheduler#5.5.1/main.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar-scheduler#5.5.1/main.min.js"></script>
<div id='calendar'></div>
codepen
The problem with the uneven amounts we cannot reach exactly 24:00:00, this gives a problem in the visualation.
Does anyone know a solution to this problem?
###EDIT### extra info:
When running my code I get following results:
divided in 30 parts (which mean 48 minutes) (and 48 minutes * 30 = 24:00:00)
divided in 21 parts (which means 1 hour and 8 minutes) (1:08 * 21 = 23:48:00)
I tried using MaxTime to limit to 23:48:00, but this does not work as expected.
Thanks in advance

Related

FullCalendar (Filemaker webviewer) has lost interactivity when rendered, I think it is to do with perform javascript in web viewer step

I have used the Frudens Calendar as a template here which uses fullcalendar. I have heavily modified the original file which works really well.
I have since tried to merge with an existing solution, so followed all the guidance about which order to do everything in. It all functions correctly except when the calendar is rendered it now loses the interactivity. It is for the resource timeline, the resources show correctly and show the events correctly but the navigations buttons at the top for day, month next previous etc now don't do anything. I can move an event, which updates the table but doesn't update the calendar interface until I leave the layout and go back to it. I have a refresh button on the calendar but like the other nav buttons it doesn't work.
This is the fullcalendar html:
<!DOCTYPE html>
<html>
<head>
<title>calendar</title>
<meta charset="utf-8" />
<link
href="https://use.fontawesome.com/releases/v5.0.6/css/all.css"
rel="stylesheet"
/>
<link href="https://cdn.jsdelivr.net/npm/fullcalendar-scheduler#5.3.2/main.min.css" rel="stylesheet"/>
<linkhref="/main.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar#5.3.2/main.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar-scheduler#5.3.2/main.min.js"></script>
<script>
var calendar;
document.addEventListener("DOMContentLoaded", function () {
var calendarEl = document.getElementById("calendar");
//plugins: ['interactionPlugin', 'timeGrid', 'dayGrid', 'resourceTimeline'],
calendar = new FullCalendar.Calendar(calendarEl, {
// --------------------
// FullCalendar Scheduler License
// https://fullcalendar.io/license/premium
// --------------------
schedulerLicenseKey: "CC-Attribution-NonCommercial-NoDerivatives",
// --------------------
// Overall Display
// --------------------
// plugins:[interactionPlugin],
headerToolbar: {
left: "refresh prev,next",
center: "title",
right:
"resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth,resourceTimelineYear resourceTimeline160Day resourceTimeGridDay",
},
customButtons: {
refresh: {
text: "Refresh",
click: function () {
FileMaker.PerformScript("T01_render_calendar", "");
},
},
},
height: window.innerHeight - 20,
aspectRatio: 1.8,
expandRows: false,
handleWindowResize: true,
windowResizeDelay: 100,
windowResize: function (arg) {
calendar.setOption("height", window.innerHeight - 20);
},
// --------------------
// Views
// --------------------
views: {
resourceTimelineDay: {
buttonText: "D",
slotDuration: "00:30:00",
slotMinTime: "00:00",
slotMaxTime: "24:00",
// titleFormat: { day:'2-digit, month: 'short'},
slotLabelFormat: [
{ weekday: 'long' },
{hour: 'numeric', minute: '2-digit', omitZeroMinute: true, meridiem: 'short'},
// // { hour: "2-digit", minute:"", meridiem },
// { hour: "2-digit", minute: "2-digit" },
],
},
resourceTimelineWeek: {
buttonText: "W",
slotDuration: "03:00",
slotMinTime: "00:00",
slotMaxTime: "24:00",
duration: { days: 7 },
// titleFormat: { day:'2-digit, month: 'short'},
weekText:"W",
slotLabelFormat: [
{ week: 'short'}, // top level of text
{ weekday: 'short', day:'2-digit' },
{hour: 'numeric', minute: '2-digit', omitZeroMinute: true, meridiem: 'short'},
// // { hour: "2-digit", minute:"", meridiem },
// { hour: "2-digit", minute: "2-digit" },
],
},
resourceTimelineMonth: {
buttonText: "M",
},
resourceTimelineYear: {
buttonText: "Y",
},
resourceTimeline160Day: {
buttonText: "D(160)",
slotDuration: "06:00",
slotMinTime: "00:00",
slotMaxTime: "24:00",
type: "resourceTimeline",
duration: { days: 160 },
},
resourceTimeGridDay: {
buttonText: "D",
slotDuration: "00:30:00",
slotMinTime: "00:00",
slotMaxTime: "24:00",
},
},
initialView: "resourceTimelineDay",
// --------------------
// Date & Time
// --------------------
slotMinTime: "00:00",
slotMaxTime: "24:00",
// scrollTime: "09:00",
firstDay: 1,
nowIndicator: true,
// --- Date Nav Links ---
navLinks: false, // can click day/week names to navigate views
// navLinkDayClick: function (date, jsEvent) {
// alert(date);
// calendar.changeView("resourceTimelineDay", date);
// FileMaker.PerformScript("datePicker_select", dateConvert(date));
// },
// navLinkWeekClick: function (weekStart, jsEvent) {
// calendar.changeView("resourceTimelineWeek", weekStart);
// FileMaker.PerformScript(
// "datePicker_select",
// dateConvert(weekStart)
// );
// },
// --- Week Numbers ---
weekNumbers: true,
// --- Date Clicking & Selecting ---
selectable: true,
selectMirror: true,
// dateClick: function (arg) {
// alert("click");
// alert(arg.dateStr);
// },
select: function (arg) {
const argJson = JSON.stringify(arg);
FileMaker.PerformScript("fullCalendar_select", argJson);
calendar.unselect();
},
// --------------------
// Events
// --------------------
// --- Event Clicking & Hovering ---
editable: true,
eventClick: function (arg) {
const argJson = JSON.stringify(arg);
FileMaker.PerformScript("fullCalendar_eventClick", argJson);
},
// --- Event Dragging & Resizing ---
eventResourceEditable: true,
eventDrop: function (arg) {
const argJson = JSON.stringify(arg);
FileMaker.PerformScript("fullCalendar_eventDrop", argJson);
},
eventResize: function (arg) {
const argJson = JSON.stringify(arg);
FileMaker.PerformScript("fullCalendar_eventResize", argJson);
},
// --- Event Popover ---
dayMaxEvents: true, // allow "more" link when too many events
// --------------------
// Resources
// --------------------
resourceOrder: "title",
resourceAreaWidth: "15%",
// --------------------
// International
// --------------------
locale: "en",
timeZone: "Europe/London",
});
calendar.render();
});
function setResourcesEventSources(fmParams) {
const obj = JSON.parse(fmParams);
if (obj.option) {
for (let key in obj.option) {
calendar.setOption(key, obj.option[key]);
}
}
calendar.setOption("resources", obj.resources);
calendar.setOption("eventSources", obj.eventSources);
calendar.gotoDate(obj.gotoDate);
}
function dateConvert(date) {
const y = date.getFullYear();
const m = date.getMonth() + 1;
const d = date.getDate();
return y + "-" + m + "-" + d;
}
</script>
<style>
html,
body {
overflow: hidden; /* don't do scrollbars */
font-family: Avenir, Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
margin: 0;
padding: 0;
},
</style>
</head>
<body>
<div id="calendar"></div>
</body>
</html>
†
I think the issue is somewhere here in the render calendar script:
Script snippet
Any help would be much appreciated.
It's weird you say that the interface doesn't update after you move an event from one area to another. Isn't that the update?
Full Calendar allows for the drag drop, which is the update. The eventDrop method does updating of the underlying record, but the event should move.
I'm also interested in why your prev / nav buttons don't work. I see nothing that prevents that.
Maybe this is the culprit:
calendar.setOption("resources", obj.resources);
calendar.setOption("eventSources", obj.eventSources);
According to the FC documentation of setOption, setting resources and eventSources is not available in this manner. It has to be done another way.
Here you have to use the addEventSource or refretchEvents methods. And those are a bit tricky when using FileMaker as the data source. They can be done, and the Claris Full Calendar Add-on employs a method. But it's a bit roundabout.
I can provide more detail if you wish.
One more thing: in your FM Script, why the Go to Field[] step at the end? I never use that when I'm working with web viewer stuff.
J Brown, thank you so much for your help with this.
For anyone else, the issue was with converting the date format to ISO from FM.
Not sure why it worked in the original file, maybe because of where it was originally written was not in the UK. We changed a custom function that simply converted the format of the system date.
This was a useful resource: https://community.jsinfm.com/home

Alternative option for eventAfterAllRender in FullCalendar v5.x

In FullCalendar v3, there has an option to catch after loading all events.
eventAfterAllRender
It seems removed in v4. As saying here:
https://fullcalendar.io/docs/v4/upgrading-from-v3
Here has a code snippet to prepare a demo calendar in v5.
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<link href='https://cdn.jsdelivr.net/npm/fullcalendar#5.5.1/main.min.css' rel='stylesheet' />
<script src='https://cdn.jsdelivr.net/npm/fullcalendar#5.5.1/main.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
initialDate: '2020-09-12',
navLinks: true, // can click day/week names to navigate views
businessHours: true, // display business hours
editable: true,
selectable: true,
events: [
{
title: 'Business Lunch',
start: '2020-09-03T13:00:00',
constraint: 'businessHours'
},
{
title: 'Meeting',
start: '2020-09-13T11:00:00',
constraint: 'availableForMeeting', // defined below
color: '#257e4a'
},
{
title: 'Conference',
start: '2020-09-18',
end: '2020-09-20'
},
{
title: 'Party',
start: '2020-09-29T20:00:00'
},
// areas where "Meeting" must be dropped
{
groupId: 'availableForMeeting',
start: '2020-09-11T10:00:00',
end: '2020-09-11T16:00:00',
display: 'background'
},
{
groupId: 'availableForMeeting',
start: '2020-09-13T10:00:00',
end: '2020-09-13T16:00:00',
display: 'background'
},
// red areas where no events can be dropped
{
start: '2020-09-24',
end: '2020-09-28',
overlap: false,
display: 'background',
color: '#ff9f89'
},
{
start: '2020-09-06',
end: '2020-09-08',
overlap: false,
display: 'background',
color: '#ff9f89'
}
]
});
calendar.render();
});
</script>
<style>
body {
margin: 40px 10px;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
#calendar {
max-width: 1100px;
margin: 0 auto;
}
</style>
</head>
<body>
<div id='calendar'></div>
</body>
</html>
Codepen: https://codepen.io/wetruck/pen/poEXEve
Is there any option to perform an action after loading all events in v5?
I'm actually using a html loader. It's showing with the page load. But after loading all events, it should be removed.
For this situation where you have a loader you want to show and hide, please see the loading callback option for something which will do the job - you can use that callback to make a loader show/hide when the AJAX part of the task starts and stops.
e.g.
loading: function( isLoading ) {
if (isLoading == true) {
//show your loader
} else {
//hide your loader
}
}
Unlike the old eventAfterAllRender it starts and stops on the start/end of the AJAX request and doesn't cover the rendering of the events by fullCalendar, but that's normally very fast unless you have an absurd number of events being downloaded for a single time period.

How to implement recurring event with all day set to true?

I am facing an issue while implementing fullcalendar. I used fullcalendar plugin for allowing the user to add task and events and with the respective option, all day, recurring every week, every day, every month and every year.
For the above-mentioned functionality, I referred two SO post
Recurring Events in Full Calendar (For repeating weekly)
Repeat full calendar events daily, monthly and yearly.
While creating an all-day event with recurring every week I am facing an issue which was addressed in Issue #4173 for which I have created a demo here
I also checked v4 and I found it will work for me a demo in v4 here, but I have some other concern here, I am working on a live website and there I can't revamp and opt to implement v4 it is a complex system need to look into all aspect before opting to revamp so is there any hack to implement the same in v3 is there anything which I can manually edit in the locally stored file or patch it for fixing this?
$(function() {
let defaultEvents = [{
id: 230,
title: 'all day with every week (range)',
start: '00:00:00',
end: '23:59:59',
dow: [2],
allDay: true,
ranges: [{
start: "2018-12-10",
end: "2018-12-26"
}]
}, ];
$('#calendar').fullCalendar({
defaultView: 'month',
header: {
left: 'prev,next today',
center: 'title',
right: 'agendaWeek,agendaDay'
},
eventSources: [defaultEvents],
eventRender: function(event, element, view) {
if (event.ranges) {
console.log(event.ranges)
return (event.ranges.filter(function(range) {
return (event.start.isBefore(range.end) &&
event.end.isAfter(range.start));
}).length) > 0;
}
}
});
});
html,
body {
margin: 0;
padding: 0;
font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
font-size: 14px;
}
#calendar {
max-width: 900px;
margin: 40px auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.0/fullcalendar.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.0/fullcalendar.min.js"></script>
<div id='calendar'></div>
Thank you
This issue was highlighted twice in v3 with tickets #4173 and #4399 and now it is fixed in v4 using a separate plugin for recurrence RRule. In v4 you can replicate the following event like this
{
title: 'event with every week (all day)',
allDay: true,
rrule: {
freq: 'weekly',
dtstart: '2019-04-05',
until: '2021-04-05'
},
}
here is the fiddle

Add more events to fullcalendar when dragging starts

I need to be able to let users move some events around on my fullcalendar. And I want to go to server and fetch counterparties' busy times and display them as background events on the calendar when the dragging is going on. However, when I call .fullcalendar('renderEvents', [...]) while the dragging is happening, the dragging mechanism within fullcalendar breaks and stops.
Is there a way to either add events without breaking dragging or some other way highlight busy times that have to be retrieved with ajax call?
The example is here: https://jsbin.com/qikiganelu/1/edit?js,output. Try dragging 'Meeting with Bob'.
$(function() { // document ready
$('#calendar').fullCalendar({
header: {
left: '',
center: '',
right: ''
},
defaultView: 'agenda',
duration: {days: 2},
allDaySlot: false,
defaultDate: '2017-04-27',
minTime: '9:00',
maxTime: '17:00',
events: [
{
title: 'Keynote',
start: '2017-04-27T09:00',
end: '2017-04-27T11:00',
editable: false,
color: "gray",
},
{
title: 'Meeting with Bob',
start: '2017-04-27T12:30',
end: '2017-04-27T13:00',
editable: true,
},
],
eventDragStart: function(event, jsEvent, ui, view){
// fetch Bob's busy times and add them as background events
var busyTimes = [
{
start: '2017-04-27T14:00',
end: '2017-04-27T16:00',
rendering: 'background',
},
{
start: '2017-04-28T9:00',
end: '2017-04-28T12:00',
rendering: 'background',
}
];
$('#calendar').fullCalendar('renderEvents', busyTimes);
},
});
});
body {
margin: 40px 10px;
padding: 0;
font-family: "Lucida Grande",Helvetica,Arial,Verdana,sans-serif;
font-size: 14px;
}
#calendar {
max-width: 900px;
margin: 0 auto;
}
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<link href='https://fullcalendar.io/js/fullcalendar-3.4.0/fullcalendar.css' rel='stylesheet' />
<link href='https://fullcalendar.io/js/fullcalendar-3.4.0/fullcalendar.print.css' rel='stylesheet' media='print' />
<script src='//cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='https://fullcalendar.io/js/fullcalendar-3.4.0/fullcalendar.js'></script>
<!-- the code from the JavaScript tab will go here -->
<!-- the code from the CSS tab will go here -->
</head>
<body>
<div id='calendar'></div>
</body>
</html>
As a workaround, try preloading all the background events, but hiding them via CSS until the drag operation happens. For instance:
// hide all background events by default
.fc-bgevent {
display: none;
}
// redisplay once "show-background-events" class toggled on
.fc-bgevent.show-background-events {
display: block;
}
Show / hide the background events by toggling the .show-background-events class like so:
eventDragStart: function(event, jsEvent, ui, view){
$(".fc-bgevent").addClass("show-background-events");
},
eventDragStop: function(event, jsEvent, ui, view){
$(".fc-bgevent").removeClass("show-background-events");
}
Example at: https://jsbin.com/vuvacisibu/1/edit?css,js,output
My bad, I now see the problem. And your mistake is the place you put your $('#calendar').fullCalendar('renderEvents', busyTimes); and also the way you write the array, I also changed the ISO8601 time string a bit to be sure.
You can remove the seconds from the time string and write 2017-04-27T12:35Z instead of 2017-04-27T12:35:02Z for example
<script>
$(function() { // document ready
$('#calendar').fullCalendar({
header: {
left: '',
center: '',
right: ''
},
defaultView: 'agenda',
duration: {days: 2},
allDaySlot: false,
defaultDate: '2017-04-27',
minTime: '9:00',
maxTime: '17:00',
events: [
{
title: 'Keynote',
start: '2017-04-27T09:00',
end: '2017-04-27T10:00',
editable: false,
color: "gray",
},
{
title: 'Meeting with Bob',
start: '2017-04-27T10:35:02Z',
end: '2017-04-27T11:35:02Z',
editable: true,
},
],
eventDragStart: function(event, jsEvent, ui, view){
}
});
//this is the new place for the fetching and calling renderEvents
// fetch Bob's busy times and add them as background
var busyTimes = [
{title: 'Event One', start: '2017-04-27T12:35:02Z', end: '2017-04-27T13:35:02Z'},
{title: 'Event Two', start: '2017-04-27T14:35:02Z', end: '2017-04-27T15:35:02Z'}
];
$('#calendar').fullCalendar('renderEvents', busyTimes);
});
</script>

Fullcalendar move only by 1 day (prev/next) in week view

Is there a way in fullcalendar on the week view to move by 1 day (next/prev buttons) instead of jumping 1 week back and forth?
The reason behind is because when I create an event on the week view I am limited to the last day and can't prolong it to the next week...
They now have added dateIncrement as a option.
$('#calendar').fullCalendar({
header: {
left: 'today prev,next',
center: 'title',
right: 'CustomW,CustomF,CustomS',
},
views: {
CustomW: {
type: 'timelineWeek',
duration: { days: 7 },
buttonText: 'Week',
dateIncrement: { days: 1 },
},
CustomF: {
type: 'timelineWeek',
duration: { days: 15 },
buttonText: '15 day',
dateIncrement: { days: 4 },
},
CustomS: {
type: 'timelineMonth',
duration: { days: 30 },
buttonText: 'Month',
dateIncrement: { days: 10 },
},
},
Okay I figured out how to make this work for both subtraction and addition. I had to alter the fullcalendar.js file itself which means there could be some other complications as I have not tested this beyond clicking the next and previous buttons. I would not recommend doing this approach if you plan on utilizing more than one view.
Force currentview to change on click
Comment out lines 9741 - 9747 and 9759
This allows the currentview to change when clicking the next button even though you haven't actually left the currentview
Previous Click
Line 7931 needs to be changed to
date.clone().startOf('day').subtract(1)
Next Click
Line 7939 needs to change to
date.clone().startOf('day').add(1, 'day')
You can create custom view like this:
$('#calendar').fullCalendar({
header: {
center: 'month,basicWeekOneDay' // buttons for switching between views
},
views: {
basicWeekOneDay: {
type: 'basicWeek',
duration: { days: 1 },
buttonText: '1 day'
}
}
});
Here is fiddle for the same:
https://jsfiddle.net/raj20090/j99f7zqw/2/

Categories