import Gantt from '../build-gantt/lib/Gantt/view/Gantt.js';
import TaskModel from '../build-gantt/lib/Gantt/model/TaskModel.js';
import ProjectModel from '../build-gantt/lib/Gantt/model/ProjectModel.js';
import Toast from '../build-gantt/lib/Core/widget/Toast.js';
import DateHelper from '../build-gantt/lib/Core/helper/DateHelper.js';
import StringHelper from '../build-gantt/lib/Core/helper/StringHelper.js';
import '../build-gantt/lib/Gantt/column/AllColumns.js';
import Column from '../build-gantt/lib/Grid/column/Column.js';
import ColumnStore from '../build-gantt/lib/Grid/data/ColumnStore.js';
import LocaleManager from '../build-gantt/lib/Core/localization/LocaleManager.js';
import Localizable from '../build-gantt/lib/Core/localization/Localizable.js';
import '../build-gantt/lib/Scheduler/feature/TimeRanges.js';
import '../build-gantt/lib/Gantt/feature/Baselines.js';
import '../build-gantt/lib/SchedulerPro/feature/DependencyEdit.js';
import '../build-gantt/lib/Grid/feature/Filter.js';
import '../build-gantt/lib/Gantt/feature/Labels.js';
import '../build-gantt/lib/Gantt/feature/ProjectLines.js';
import '../build-gantt/lib/Gantt/feature/ProgressLine.js';
import '../build-gantt/lib/Gantt/feature/Rollups.js';
import '../build-gantt/lib/Gantt/feature/TaskEdit.js';
import '../build-gantt/lib/Gantt/feature/export/PdfExport.js';
import '../build-gantt/lib/Grid/feature/experimental/ExcelExporter.js';
import '../build-gantt/lib/Core/widget/ButtonGroup.js';
import '../build-gantt/lib/Scheduler/widget/UndoRedo.js';
LocaleManager.applyLocale("En");
// region Label configs
const
topLabel = {
field : 'name',
editor : {
type : 'textfield'
}
},
bottomLabel = {
field : 'startDate',
renderer : function({ taskRecord }) {
return DateHelper.format(taskRecord.startDate, 'DD-MMM-Y');
}
};
// endregion
// using module bundle
LocaleManager.locale = userLocale;
// also possible to reach it from the gantt instance
//gantt.localeManager.locale = 'Fr';
const headerTpl = ({currentPage, totalPages}) => `
<div class="demo-export-header">
<img src="/assets/img/logo.png" />
<dl>
<dt>Date: ${DateHelper.format(new Date(), 'll LT')}</dt>
<dd>${(currentPage && totalPages) ? `Page: ${currentPage + 1}/${totalPages}` : ''}</dd>
</dl>
</div>`;
const footerTpl = () => '<div class="demo-export-footer"><h3>© 2020 PMS</h3></div>';
class StatusColumn extends Column {
static get $name() {
return 'StatusColumn';
}
static get type() {
return 'statuscolumn';
}
static get isGanttColumn() {
return true;
}
static get defaults() {
return {
// Set your default instance config properties here
field : 'status',
text : 'Status',
editor : false,
cellCls : 'b-status-column-cell',
htmlEncode : false,
filterable : {
filterField : {
type : 'combo',
items : ['Not Started', 'Started', 'Completed', 'Late']
}
}
};
}
renderer({ isExport }) {
}
//endregion
renderer({ record ,isExport}) {
const status = record.status;
if (isExport) {
return record.status;
}
else {
// widget rendering routine
return status ? {
tag : 'i',
className : `b-fa b-fa-circle ${status}`,
html : status
} : '';
}
}
}
ColumnStore.registerColumnType(StatusColumn);
class MyTaskModel extends TaskModel {
static get fields() {
return [
{
name : 'weight',
type : 'number',
convert(value, record) {
// call standard number field convert() method
value = this.constructor.prototype.convert.call(this, value, record);
value = value ? Number(value) : 0;
if(typeof(record) != "undefined") {
const parent = record.parent;
// sum up total weight for children
if (parent) {
let sum = value;
parent.children.forEach(task => {
if (task !== record) {
sum += task.weight;
}
});
// reduce if it's >= 100
if (sum > 100) {
value -= sum - 100;
}
}
}
return value;
}
}
]
}
* calculatePercentDone(proposedValue) {
// if the event has sub-events
if (yield * this.hasSubEvents()) {
let parentWeight = 0;
// get sub-events
const subEvents = yield * this.subEventsIterable();
for (const subEvent of subEvents) {
// get the sub-event percentDone
const percentDone = yield subEvent.$.percentDone;
parentWeight += subEvent.weight * percentDone / 100;
}
return parentWeight;
}
// for leaf tasks use default logic
return yield * super.calculatePercentDone(proposedValue);
}
get isLate() {
return this.deadline && Date.now() > this.deadline;
}
get status() {
let status = 'Not started';
if (this.isCompleted) {
status = 'Completed';
}
else if (this.endDate < Date.now() || (this.startDate<Date.now() && !this.isStarted)) {
status = 'Late';
}
else if (this.isStarted) {
status = 'Started';
}
return status;
}
}
function setBaseline(index) {
gantt.taskStore.setBaseline(index);
}
function toggleBaselineVisible(index, visible) {
//gantt.element.classList[visible ? 'remove' : 'add'](`b-hide-baseline-${index}`);
console.log(`baseline-${index}`);
var elements=document.getElementsByClassName(`baseline-${index}`);
for (let i = 0; i < elements.length; i++) {
elements[i].classList[visible ? 'remove' : 'add'](`hide-baseline`);
}
}
let project = new ProjectModel({
taskModelClass: MyTaskModel,
autoSync: true,
transport: {
load: {
url: ""
//url: '../assets/build-gantt/_datasets/launch-saas.json'
},
sync: {
url: ""
}
},
autoLoad: true,
autoCalculatePercentDoneForParentTasks: false,
// The State TrackingManager which the UndoRedo widget in the toolbar uses
stm: {
autoRecord: true
},
});
let baselines = JSON.parse(baselinesStr);
let baselinesList=[];
let index=1;
baselines.forEach(function(item){
console.log("Baselines:");
console.log(item);
baselinesList.push(
{
checked: true,
text: item.name,
onToggle({checked}) {
toggleBaselineVisible(item.id, checked);
}
}
);
});
const readOnly = (projectStatus === STATUS_COMPLETED || projectStatus === STATUS_FAILED || userRole===ROLE_NORMAL) ? true : false;
const hideContextMenu=(projectStatus === STATUS_COMPLETED || projectStatus === STATUS_FAILED || userRole===ROLE_NORMAL || projectStatus === STATUS_ON_TRACK || projectStatus === STATUS_DELAYED) ? true : false;
function isFieldReadOnly(field) {
var readOnly = false;
switch (field) {
case "percentdone":
readOnly = (projectStatus === STATUS_PLANNING || projectStatus === STATUS_ON_HOLD || projectStatus === STATUS_REJECTED);
break;
case "":
// code block
break;
default:
readOnly = (projectStatus === STATUS_ON_TRACK || projectStatus === STATUS_DELAYED);
// code block
}
return readOnly;
}
const apiRequestAction = async (method, url, headers, body) => {
let fetchObject = {
method,
headers: { 'Content-Type': 'application/json', ...headers }
};
if (body) fetchObject = { ...fetchObject, body: JSON.stringify(body) };
const response = await fetch(url, { ...fetchObject });
return await response.json();
};
let gantt = new Gantt({
project: project,
readOnly: readOnly,
startDate: new Date(projectStartDate),
endDate: new Date(projectEndDate),
columns: [
{type: 'sequence',text: '#' },
{type: 'wbs',
renderer({ value }) {
return String(value);
}
},
{type: 'name', field: 'name', text: Localizable().L('L{NameColumn.Name}'), editor: !isFieldReadOnly("name"), filterable: true },
{
type: 'number',
min: 0,
max: 100,
text:Localizable().L('Weight'),
align: 'center',
field: 'weight',
editor: !isFieldReadOnly("weight"),
filterable: true
},
{type: 'startdate', text: Localizable().L('L{StartDateColumn.Start}'), editor: !isFieldReadOnly("startdate"), filterable: true,min: projectStartDate,max: projectEndDate},
{ type:'enddate', text: Localizable().L('L{EndDateColumn.Finish}'), editor: !isFieldReadOnly("enddate"), filterable: true,min: projectStartDate,max: projectEndDate },
{type: 'duration', text: Localizable().L('L{DurationColumn.Duration}'), editor: !isFieldReadOnly("duration"), filterable: true },
{ type : 'statuscolumn', filterable: true},
{type: 'resourceassignment', width: 120, showAvatars: true, editor: !isFieldReadOnly("resourceassignment"), filterable: true },
{
type: 'percentdone',
text: Localizable().L('L{PercentDoneColumn.% Done}'),
showCircle: true,
width: 70,
editor: !isFieldReadOnly("percentdone"),
filterable: true,
renderer({ record, isExport }) {
const value = record.renderedPercentDone;
if (this.showCircle && !isExport) {
return {
className : {
'b-percentdone-circle' : 1,
'b-full' : value === 100,
'b-empty' : value === 0
},
style : {
height : this.circleHeightPercentage * this.grid.rowHeight + 'px',
width : this.circleHeightPercentage * this.grid.rowHeight + 'px',
'--gantt-percentdone-angle' : `${value / 100}turn`
},
dataset : {
value
}
};
}
return value;
}
},
{type: 'predecessor', editor: !isFieldReadOnly("predecessor"), filterable: true },
{type: 'successor', editor: !isFieldReadOnly("successor"), filterable: true },
//{ type : 'milestone' },
//{ type : 'schedulingmodecolumn' },
{type : 'calendar'},
//{type: 'constrainttype', editor: !isFieldReadOnly("constrainttype")},
//{type: 'constraintdate', editor: !isFieldReadOnly("constraintdate")},
//{type: 'date', text: 'Deadline', field: 'deadline', editor: !isFieldReadOnly("deadline"), filterable: true },
//{type: 'date', text: 'Finish', field: 'enddate', editor: !isFieldReadOnly("finish")},
{ type: 'addnew', field: 'addnew', text: 'Addnew' },
],
style: 'font-size:0.85em',
autoHeight: true,
subGridConfigs: {
locked: {flex: 3},
normal: {flex: 4}
},
listeners: {
beforeCellEditStart({editorContext}) {
return Boolean(editorContext.record.parentId);
},
beforeTaskEdit({ taskRecord, taskElement }) {
if(!taskRecord.parentId)
{
// Prevent built in editor
return false;
}
},
beforeTaskEditShow({ editor, taskRecord }) {
console.log(editor.widgetMap);
editor.widgetMap.constraintDateField.hidden=true;
editor.widgetMap.constraintTypeField.hidden=true;
editor.widgetMap.manuallyScheduledField.hidden=true;
editor.widgetMap.rollupField.hidden=true;
editor.widgetMap.divider.visible=false;
},
paint : ({ source }) => {
// find "Add New..." column
// const addNewColumn = source.columns.find(col => col.isAddNewColumn);
//console.log(addNewColumn.columnCombo.store);
// filter the column drop down list
//addNewColumn.columnCombo.store.addFilter
source.columns.findRecord('type', 'addnew').combo.store.addFilter({
id : 'my-filter',
// define filter function that will skip columns of certain types
filterBy : (column) => {
return column.id == 'earlystartdate' || column.id == 'earlyenddate' || column.id == 'lateenddate' || column.id == 'latestartdate' || column.id == 'effort' || column.id == 'totalslack' || column.id == 'milestone' || column.id == 'note' || column.id == 'schedulingmode';
}
});
}
},
features: {
criticalPaths: true,
cellEdit: {
addNewAtEnd: false,
},
rowReorder : {
listeners : {
gridRowBeforeDropFinalize({ context }) {
return Boolean(context.insertBefore.parentId);
}
}
},
filter: true,
taskEdit: {
disabled : hideContextMenu,
items: {
generalTab: {
items: {
name: { readOnly: isFieldReadOnly("name") },
startDate: { readOnly: isFieldReadOnly("startdate") },
endDate: { readOnly: isFieldReadOnly("enddate") },
duration: { readOnly: isFieldReadOnly("duration") },
statusColumn: { readOnly: isFieldReadOnly('statuscolumn') },
percentDone: { readOnly: isFieldReadOnly("percentDone") },
effort: { readOnly: isFieldReadOnly("effort") },
deadLine: { readOnly: isFieldReadOnly("deadline") },
newGeneralField: {
type: 'number',
weight: 710,
label: 'Weight',
name: 'weight',
min: 0,
max: 100,
readOnly: isFieldReadOnly('weight')
}
}
},
resourcesTab: {
items: {
resourceassignment: { readOnly: isFieldReadOnly("resourceassignment") },
}
},
advancedTab: {
items: {
constraintType: false,
constraintDate: false,
divider : false
}
}
}
},
taskMenu: {
processItems({items, taskRecord}) {
const readOnly = !taskRecord.parentId;
console.log(items);
items.add.menu.addTaskAbove.hidden =
items.add.menu.addTaskBelow.hidden =
items.editTask.hidden =
items.deleteTask.hidden =
readOnly;
//items.add.menu.subtask.hidden = !readOnly;
items.add.menu.successor.hidden=readOnly;
items.add.menu.predecessor.hidden=readOnly;
items.add.menu.milestone.hidden=readOnly;
items.convertToMilestone.hidden=readOnly;
//items.add.menu.filter.hidden=readOnly;
items.indent.hidden=readOnly;
items.outdent.hidden=readOnly;
if(typeof(items.filterStringEquals) != "undefined") {
items.filterStringEquals.hidden=readOnly;
}
console.log("Level : "+taskRecord.childLevel);
if(taskRecord.childLevel==1){
items.outdent.hidden=true;
}
console.log(hideContextMenu);
if(hideContextMenu){
return false;
}
if(!readOnly){
items.add.menu.addTaskAbove.onItem=async ({taskRecord}) => {
const task = await gantt.addTaskAbove(taskRecord);
task.name = 'New task';
task.duration = 2;
task.calendar=gantt.project.calendar.id;
gantt.project.commitAsync();
}
items.add.menu.addTaskBelow.onItem=async ({taskRecord}) => {
const task = await gantt.addTaskBelow(taskRecord);
task.name = 'New task';
task.duration = 2;
task.calendar=gantt.project.calendar.id;
gantt.project.commitAsync();
}
}
items.add.menu.subtask.onItem=async ({taskRecord}) => {
const task = await gantt.addSubtask(taskRecord);
task.name = 'New subtask';
task.duration = 2;
console.log(gantt.project.calendar.id);
task.calendar=gantt.project.calendar.id;
gantt.project.commitAsync();
console.log(task.duration);
}
},
},
// baselines : true,
baselines: {
// Custom tooltip template for baselines
template(data) {
const
me = this,
{baseline} = data,
{task} = baseline,
delayed = task.startDate > baseline.startDate,
overrun = task.durationMS > baseline.durationMS;
console.log(baseline);
let {decimalPrecision} = me;
if (decimalPrecision == null) {
decimalPrecision = me.client.durationDisplayPrecision;
}
const
multiplier = Math.pow(10, decimalPrecision),
displayDuration = Math.round(baseline.duration * multiplier) / multiplier;
return `
<div class="b-gantt-task-title">${StringHelper.encodeHtml(task.name)} (${baseline.name})</div>
<table>
<tr><td>${me.L('Start')}:</td><td>${data.startClockHtml}</td></tr>
${baseline.milestone ? '' : `
<tr><td>${me.L('End')}:</td><td>${data.endClockHtml}</td></tr>
<tr><td>${me.L('Duration')}:</td><td class="b-right">${displayDuration + ' ' + DateHelper.getLocalizedNameOfUnit(baseline.durationUnit, baseline.duration !== 1)}</td></tr>
`}
</table>
${delayed ? `
<h4 class="statusmessage b-baseline-delay"><i class="statusicon b-fa b-fa-exclamation-triangle"></i>${me.L('Delayed start by')} ${DateHelper.formatDelta(task.startDate - baseline.startDate)}</h4>
` : ''}
${overrun ? `
<h4 class="statusmessage b-baseline-overrun"><i class="statusicon b-fa b-fa-exclamation-triangle"></i>${me.L('Overrun by')} ${DateHelper.formatDelta(task.durationMS - baseline.durationMS)}</h4>
` : ''}
`;
}
},
pdfExport: {
exportServer: 'http://localhost:8080', //Print server
translateURLsToAbsolute : 'http://localhost:8080/resources', //Print server
clientURL : 'http://localhost:8080', //App server
headerTpl,
footerTpl
},
excelExporter: {
// Choose the date format for date fields
dateFormat: 'YYYY-MM-DD HH:mm'
},
/*labels : {
top: topLabel,
bottom: null,
left: null,
right: null,
labelCls: 'label-css'
}*/
},
dependencyIdField: 'wbsCode',
tbar: {
items: [
{
type: 'buttonGroup',
items: [
/*{
type: 'button',
text: 'Add Task',
onAction() {
// console.log(project.taskStore.first.appendChild({
name: 'New Task', duration: '1'
}));
}
},*/
{
color: 'b-green',
ref: 'addTaskButton',
icon: 'b-fa b-fa-plus',
text: 'Create',
tooltip: 'Create new task',
style: 'margin-right: .5em',
disabled: readOnly || isFieldReadOnly("name"),
async onAction() { //onAddTaskClick
const newTask = {name: 'New task', duration: '2', calendar: gantt.project.calendar.id};
console.log("From create task:");
console.log(gantt.project.calendar.id);
//const added = gantt.taskStore.rootNode.appendChild(newTask);
let added =project.taskStore.first.appendChild({
name: 'New Task', duration: '2',weight:'0',calendar: gantt.project.calendar.id
});
// run propagation to calculate new task fields
// await project.comitAsync();
// run propagation to calculate new task fields
await gantt.project.propagateAsync();
// scroll to the added task. Smoothly.
await gantt.scrollRowIntoView(added, {
animate: true
});
gantt.features.cellEdit.startEditing({
record: added,
field: 'name'
});
Toast.show('Created a new task, you may update it at the same or click somewhere else to avoid update');
/*Toast.show({
html: 'Created a new task, you may update it at the same or click somewhere else to avoid update',
color: 'b-light-green'
});*/
}
}
]
},
{
type: 'buttonGroup',
items: [
{
color: 'b-green',
icon: 'b-fa b-fa-pen',
text: 'Edit',
tooltip: 'Edit selected task',
disabled: readOnly || isFieldReadOnly("name"),
onAction() { //onEditTaskClick
if (gantt.selectedRecord && gantt.selectedRecord.parentId) {
gantt.editTask(gantt.selectedRecord);
}else if (gantt.selectedRecord && !gantt.selectedRecord.parentId) {
Toast.show('Sorry, you can not edit project task');
}else {
Toast.show('First select the task you want to edit');
}
}
}
]
},
{
ref: 'undoRedo',
type: 'undoredo',
items: {
transactionsCombo: null
}
},
{
type: 'buttonGroup',
items: [
{
ref: 'expandAllButton',
icon: 'b-fa b-fa-angle-double-down',
tooltip: 'Expand all',
onAction() { //onExpandAllClick
gantt.expandAll();
}
},
{
ref: 'collapseAllButton',
icon: 'b-fa b-fa-angle-double-up',
tooltip: 'Collapse all',
onAction() { //onCollapseAllClick
gantt.collapseAll();
}
}
]
},
{
type: 'buttonGroup',
items: [
{
ref: 'zoomInButton',
icon: 'b-fa b-fa-search-plus',
tooltip: 'Zoom in',
onAction() { //onZoomInClick
gantt.zoomIn();
}
},
{
ref: 'zoomOutButton',
icon: 'b-fa b-fa-search-minus',
tooltip: 'Zoom out',
onAction() { //onZoomOutClick
gantt.zoomOut();
}
},
{
ref: 'zoomToFitButton',
icon: 'b-fa b-fa-compress-arrows-alt',
tooltip: 'Zoom to fit',
onAction() {
gantt.zoomToFit({ //onZoomToFitClick
leftMargin: 50,
rightMargin: 50
});
}
},
{
ref: 'previousButton',
icon: 'b-fa b-fa-angle-left',
tooltip: 'Previous time span',
onAction() { //'up.onShiftPreviousClick'
gantt.shiftPrevious();
}
},
{
ref: 'nextButton',
icon: 'b-fa b-fa-angle-right',
tooltip: 'Next time span',
onAction() { //'up.onShiftNextClick'
gantt.shiftNext();
}
}
]
},
{
type: 'buttonGroup',
items: [
{
type: 'button',
text: 'Export to Excel',
ref: 'excelExportBtn',
icon: 'b-fa-file-export',
onAction: () => {
const filename = gantt.project.taskStore.first && gantt.project.taskStore.first.name;
gantt.features.excelExporter.export({
filename
});
}
},
{
type : 'button',
ref : 'exportButton',
icon : 'b-fa-file-export',
text : 'Export to PDF',
onClick() {
gantt.zoomToFit({ //onZoomToFitClick
leftMargin: 50,
rightMargin: 50
});
gantt.features.pdfExport.showExportDialog();
}
}
]
},
'->',
{
type : 'combo',
ref : 'calendar',
label : 'Default calendar',
items : [{ value: 'general', text: 'General' }, { value: 'business', text: 'Business' }],
flex : '0 0 17em',
text : 'Default calendar description',
readOnly:true,
onChange:({ value, oldValue }) => {
if (!oldValue) {
return;
}
console.log(value);
apiRequestAction('POST', '', {}, {"projectId":projectId,"calendar":value})
.then(res => {
//loadSpinner(false);
console.log('res => ', res);
})
.catch(err => {
//loadSpinner(false);
console.log('err => ', err);
});
if(gantt.project.taskStore.first){
}
console.log("From change calendar:");
console.log(gantt.project.getCalendar());
}
},
'->',
{
type: 'textfield',
ref: 'filterByName',
cls: 'filter-by-name',
flex: '0 0 12.5em',
// Label used for material, hidden in other themes
label: 'Find tasks by name',
// Placeholder for others
placeholder : 'Find tasks by name',
clearable: true,
keyStrokeChangeDelay: 100,
triggers: {
filter: {
align: 'end',
cls: 'b-fa b-fa-filter'
}
},
onChange({value}) { //'up.onFilterChange'
if (value === '') {
gantt.taskStore.clearFilters();
} else {
value = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
gantt.taskStore.filter({
filters: task => task.name && task.name.match(new RegExp(value, 'i')),
replace: true
});
}
}
},
{
type: 'buttonGroup',
items: [
{
type: 'button',
text: 'Show baseline',
icon: 'b-fa-bars',
iconAlign: 'end',
menu: baselinesList
}
]
},
{
type: 'checkbox',
text: 'Show baselines',
checked: true,
ref:'showBaselines',
toggleable: true,
onAction({checked}) {
gantt.features.baselines.disabled = !checked;
}
},
{
type: 'button',
ref: 'featuresButton',
icon: 'b-fa b-fa-tasks',
text: 'Settings',
tooltip: 'Toggle features',
toggleable: true,
menu: {
onItem({source: item}) { //'up.onFeaturesClick',
if (item.feature) {
const feature = gantt.features[item.feature];
feature.disabled = !feature.disabled;
} else if (item.subGrid) {
const subGrid = gantt.subGrids[item.subGrid];
subGrid.collapsed = !subGrid.collapsed;
}
},
onBeforeShow({source: menu}) { //'up.onFeaturesShow',
menu.items.map(item => {
const {feature} = item;
if (feature) {
// a feature might be not presented in the gantt
// (the code is shared between "advanced" and "php" demos which use a bit different set of features)
if (gantt.features[feature]) {
item.checked = !gantt.features[feature].disabled;
}
// hide not existing features
else {
item.hide();
}
} else if (item.subGrid) {
item.checked = gantt.subGrids[item.subGrid].collapsed;
}
});
},
// "checked" is set to a boolean value to display a checkbox for menu items. No matter if it is true or false.
// The real value is set dynamically depending on the "disabled" config of the feature it is bound to.
items: [
{
text: 'UI settings',
icon: 'b-fa-sliders-h',
menu: {
type: 'popup',
anchor: true,
cls: 'settings-menu',
layoutStyle: {
flexDirection: 'column'
},
onBeforeShow({source: menu}) { //'up.onSettingsShow',
const {rowHeight, barMargin, duration} = menu.widgetMap;
rowHeight.value = gantt.rowHeight;
barMargin.value = gantt.barMargin;
barMargin.max = (gantt.rowHeight / 2) - 5;
duration.value = gantt.transitionDuration;
},
items: [
{
type: 'slider',
ref: 'rowHeight',
text: 'Row height',
width: '12em',
showValue: true,
min: 30,
max: 70,
onInput({value, source}) { //'up.onRowHeightChange'
gantt.rowHeight = value;
source.owner.widgetMap.barMargin.max = (value / 2) - 5;
}
},
{
type: 'slider',
ref: 'barMargin',
text: 'Bar margin',
width: '12em',
showValue: true,
min: 0,
max: 10,
onInput({value}) { //'up.onBarMarginChange'
gantt.barMargin = value;
}
},
{
type: 'slider',
ref: 'duration',
text: 'Animation duration ',
width: '12em',
min: 0,
max: 2000,
step: 100,
showValue: true,
onInput({value}) { //'up.onAnimationDurationChange'
gantt.transitionDuration = value;
styleNode.innerHTML = `.b-animating .b-gantt-task-wrap { transition-duration: ${value / 1000}s !important; }`;
}
}
]
}
},
{
text: 'Draw dependencies',
feature: 'dependencies',
checked: false
},
{
text: 'Task labels',
feature: 'labels',
checked: false
},
{
text: 'Critical paths',
feature: 'criticalPaths',
tooltip: 'Highlight critical paths',
checked: false
},
{
text: 'Project lines',
feature: 'projectLines',
checked: false
},
{
text: 'Highlight non-working time',
feature: 'nonWorkingTime',
checked: false
},
/* {
text: 'Enable cell editing',
feature: 'cellEdit',
checked: false
}, */
/* {
text: 'Show baselines',
feature: 'baselines',
checked: false
}, */
{
text: 'Show rollups',
feature: 'rollups',
checked: false
},
{
text: 'Show progress line',
feature: 'progressLine',
checked: false
},
{
text: 'Hide schedule',
cls: 'b-separator',
subGrid: 'normal',
checked: false
}
]
}
}
]
},
appendTo: document.getElementById('granttId')
});
/*gantt.taskStore.on({
catchAll(event) {
if(event.type ==='add'){
console.log('Event Listener catch All (ADD TASK)....', event.type, event)
console.log(event.records[0]);
}
}
})*/
gantt.taskStore.on({
add:(event) => {
console.log('TaskStore Event ADD', event.records[0]);
let record=event.records[0];
let value = record.weight;
value = value ? Number(value) : 0;
if(typeof(record) != "undefined") {
const parent = record.parent;
// sum up total weight for children
if (parent) {
let sum = value;
parent.children.forEach(task => {
if (task !== record) {
sum += task.weight;
}
});
// reduce if it's >= 100
if (sum > 100) {
value -= sum - 100;
}
}
}
record.weight=value;
},
});
gantt.project.on({
load:(event) => {
updateProjectCalendar();
}
});
function updateProjectCalendar(){
console.log(gantt.project.calendar);
gantt.tbar.widgetMap.calendar.value=gantt.project.calendar.id;
}
gantt.tbar.widgetMap.showBaselines.checked=false;