FullCalendar Timeline View(v4)
The Scheduler add-on provides a new view called “timeline view” with a customizable horizontal time-axis and resources as rows.
1. 先安装fullcalendar和用到的插件
npm install --save @fullcalendar/core @fullcalendar/resource-timeline @fullcalendar/interaction
2.在使用时导入
import {Calendar} from '@fullcalendar/core';
import resourceTimelinePlugin from '@fullcalendar/resource-timeline';
import interactionPlugin from '@fullcalendar/interaction';
import '@fullcalendar/core/main.css';
import '@fullcalendar/timeline/main.css';
import '@fullcalendar/resource-timeline/main.css';
3. 初始化Calendar时,添加使用的插件
plugins: [interactionPlugin, resourceTimelinePlugin],
4.最终实现资源/事件的添加删除.
上代码.
import {Calendar} from '@fullcalendar/core';
import resourceTimelinePlugin from '@fullcalendar/resource-timeline';
import interactionPlugin from '@fullcalendar/interaction';
import '@fullcalendar/core/main.css';
import '@fullcalendar/timeline/main.css';
import '@fullcalendar/resource-timeline/main.css'; // import zh_cn from '@fullcalendar/core/locales/zh-cn';
let option = {
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
plugins: [interactionPlugin, resourceTimelinePlugin],
defaultView: 'resourceTimeline',
now: '2019-03-07',
// locale: zh_cn,
selectable: true,
selectHelper: true,
editable: true, // enable draggable events
eventResourceEditable: false,
aspectRatio: 1,
// height: 440,
contentHeight: 440,
resourceAreaWidth: '120px',
eventOverlap: false,
selectOverlap: false,
eventTextColor: '#fff',
displayEventTime: true,
displayEventEnd: true,
slotLabelFormat: {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short',
hour12: false,
},
eventTimeFormat: {
hour: 'numeric',
minute: '2-digit',
meridiem: 'narrow',
hour12: false,
},
header: {
left: '',
center: '',
right: '',
},
resourceLabelText: '姓名',
resources: [],
events: [],
};
/**
* {Object} option , onSelect: function onEventClick: function ,
*/ class Timeline {
constructor(el, opt = {}, callBack = () => {}) {
this.callBack = callBack;
console.log('timeline -init');
this._option = Object.assign(
{
select: info => this.select(info),
dateClick: info => this.dateClick(info),
eventClick: info => this.eventClick(info),
eventMouseEnter: info => this.eventMouseEnter(info),
eventMouseLeave: info => this.eventMouseLeave(info),
eventResize: info => this.eventResize(info),
eventDrop: info => this.eventDrop(info),
resourceRender: info => this.resourceRender(info),
eventRender: info => this.eventRender(info),
eventDestroy: info => this.eventDestroy(info),
},
option,
opt
);
console.log('timeline-option==>>', this._option);
this.calendar = new Calendar(el, this._option);
this.render(); let currentDate = new Date(this._option.now);
let end = new Date().setDate(currentDate.getDate());
if (currentDate.getHours() !== 0) {
end = new Date().setDate(currentDate.getDate() + 1);
}
console.table('start, end', currentDate, new Date(end));
this.setOption('visibleRange', {
start: currentDate,
end: end,
});
} /**
* @param {Object} value
*/
setOption(key, value) {
this.calendar.setOption(key, value);
this._option[key] = value;
} // methods
render() {
this.calendar.render();
}
addResource(resource) {
if (!resource) {
return;
}
this.calendar.addResource(resource);
}
removeResource(resource, e) {
if (!this._option.editable) {
return;
}
this._option.onRemoveResource && this._option.onRemoveResource(resource);
let events = resource.getEvents();
events.forEach(event => {
event.remove();
});
resource.remove();
this.getResult(); e.target.removeEventListener('click', this.removeResource);
}
addEvent(event) {
if (!event) {
return;
}
let tmp = this.calendar.getEventById(event.id);
if (tmp) {
for (let key in event) {
if (tmp.extendedProps[key]) {
tmp.setExtendedProp(key, event[key]);
continue;
}
if (tmp[key]) {
tmp.setProp(key, event[key]);
}
}
} else {
this.calendar.addEvent(event);
console.log('addd', event);
}
}
removeEvent(eventId) {
let event = this.calendar.getEventById(eventId);
if (event) {
event.remove();
this.getResult();
}
} destroy() {
this.calendar.destroy();
console.log('timeline destroy >>>>>>>');
}
getResult() {
let resources = this.calendar.getResources();
let result = [];
resources.map(item => {
let tmp = {
resource: item,
events: item.getEvents(),
};
result.push(tmp);
}); this.callBack && this.callBack(result);
}
isValid(event) {
let now = this._option.now;
let start = new Date(event.start).getTime();
let end = new Date(event.end).getTime();
let startH = new Date(now).getHours();
let startD = new Date(now).getDate();
let crossDate = new Date(now);
crossDate.setDate(startD);
crossDate.setHours(23);
let endPoint = crossDate.getTime();
if (startH !== 0) {
crossDate.setDate(startD + 1);
crossDate.setHours(startH);
endPoint = crossDate.getTime();
}
if (start < now || end < now || start > endPoint || end > endPoint) {
return false;
}
return true;
}
/**
callbacks
*/
select(info) {
if (!this.isValid({start: info.start, end: info.end})) {
// info.revert();
return;
}
this._option.onSelect && this._option.onSelect(info);
}
dateClick(arg) {
console.log('dateClick', arg.date, arg.resource ? arg.resource.id : '(no resource)');
}
eventClick(info) {
this._option.onEventClick && this._option.onEventClick(info);
}
eventMouseEnter(info) {
this._option.onEventMouseEnter && this._option.onEventMouseEnter(info);
}
eventMouseLeave(info) {
this._option.onEventMouseLeave && this._option.onEventMouseLeave(info);
}
eventResize(info) {
if (!this.isValid(info.event)) {
info.revert();
}
// this.getResult();
}
eventDrop(info) {
if (!this.isValid(info.event)) {
info.revert();
}
// this.getResult();
}
resourceRender(info) {
let dom = info.el;
dom.style = dom.style + ';position:relative;';
let close = document.createElement('i');
close.classList.add('iconfont', 'icon-c');
close.style = 'position:absolute;right:10px;top:50%;transform:translateY(-50%);font-size: 10px;';
close.addEventListener('click', e => this.removeResource(info.resource, e));
dom.appendChild(close);
}
eventRender(info) {
this.getResult();
} eventDestroy(info) {
// this.getResult();
// console.log('eventDestroy', info);
}
} export default Timeline;
使用(示例)
let timelineView = new Timeline(
document.querySelector('#time-line-day'), {
now: new Date(),
onSelect: info => {
let event = {
id: this.eventId,
title: this.eventId,
resourceId: info.resource.id,
start: info.start,
end: info.end,
};
timelineView.addEvent(event); },
onRemoveResource: info => { },
onEventClick: info => {
let event = {
id: info.event.id,
title: info.event.title,
resourceId: info.event.getResources()[0].id,
start: info.event.start,
end: info.event.end,
};
let resourceId = info.event.getResources()[0].id; },
},
result => { }
);
FullCalendar插件 plug-index