in src/gantt.ts [839:1103]
private static createTasks(
dataView: DataView,
taskTypes: TaskTypes,
host: IVisualHost,
formatters: GanttChartFormatters,
colors: IColorPalette,
settings: GanttSettings,
taskColor: string,
localizationManager: ILocalizationManager,
isEndDateFillled: boolean): Task[] {
let tasks: Task[] = [],
addedParents: string[] = [];
const values: GanttColumns<any> = GanttColumns.getCategoricalValues(dataView);
if (!values.Task) {
return tasks;
}
const colorHelper: ColorHelper = new ColorHelper(colors, Gantt.LegendPropertyIdentifier);
const groupValues: GanttColumns<DataViewValueColumn>[] = GanttColumns.getGroupedValueColumns(dataView);
const sortingOptions: SortingOptions = Gantt.getSortingOptions(dataView);
let collapsedTasks: string[] = JSON.parse(settings.collapsedTasks.list);
let durationUnit: string = settings.general.durationUnit;
let duration: number = settings.general.durationMin;
let taskProgressShow: boolean = settings.taskCompletion.show;
let endDate: Date = null;
values.Task.forEach((categoryValue: PrimitiveValue, index: number) => {
let color: string = taskColor || Gantt.DefaultValues.TaskColor;
let completion: number = 0;
let taskType: TaskTypeMetadata = null;
let wasDowngradeDurationUnit: boolean = false;
let tooltips: VisualTooltipDataItem[] = [];
let stepDurationTransformation: number = 0;
const selectionBuilder: ISelectionIdBuilder = host
.createSelectionIdBuilder()
.withCategory(dataView.categorical.categories[0], index);
if (groupValues) {
groupValues.forEach((group: GanttColumns<DataViewValueColumn>) => {
let maxCompletionFromTasks: number = _.max(values.Completion);
maxCompletionFromTasks = maxCompletionFromTasks > Gantt.ComplectionMax ? Gantt.ComplectionMaxInPercent : Gantt.ComplectionMax;
if (group.Duration && group.Duration.values[index] !== null) {
taskType = _.find(taskTypes.types,
(typeMeta: TaskTypeMetadata) => typeMeta.name === group.Duration.source.groupName);
if (taskType) {
selectionBuilder.withCategory(taskType.selectionColumn, 0);
color = colorHelper.getColorForMeasure(taskType.columnGroup.objects, taskType.name);
}
duration = group.Duration.values[index] > settings.general.durationMin ? group.Duration.values[index] as number : settings.general.durationMin;
if (duration && duration % 1 !== 0) {
durationUnit = DurationHelper.downgradeDurationUnit(durationUnit, duration);
stepDurationTransformation =
GanttDurationUnitType.indexOf(settings.general.durationUnit) - GanttDurationUnitType.indexOf(durationUnit);
duration = DurationHelper.transformDuration(duration, durationUnit, stepDurationTransformation);
wasDowngradeDurationUnit = true;
}
completion = ((group.Completion && group.Completion.values[index])
&& taskProgressShow
&& Gantt.convertToDecimal(group.Completion.values[index] as number, settings.taskCompletion.maxCompletion, maxCompletionFromTasks)) || null;
if (completion !== null) {
if (completion < Gantt.ComplectionMin) {
completion = Gantt.ComplectionMin;
}
if (completion > Gantt.ComplectionMax) {
completion = Gantt.ComplectionMax;
}
}
} else if (group.EndDate && group.EndDate.values[index] !== null) {
taskType = _.find(taskTypes.types,
(typeMeta: TaskTypeMetadata) => typeMeta.name === group.EndDate.source.groupName);
if (taskType) {
selectionBuilder.withCategory(taskType.selectionColumn, 0);
color = colorHelper.getColorForMeasure(taskType.columnGroup.objects, taskType.name);
}
endDate = group.EndDate.values[index] ? group.EndDate.values[index] as Date : null;
if (typeof (endDate) === "string" || typeof (endDate) === "number") {
endDate = new Date(endDate);
}
completion = ((group.Completion && group.Completion.values[index])
&& taskProgressShow
&& Gantt.convertToDecimal(group.Completion.values[index] as number, settings.taskCompletion.maxCompletion, maxCompletionFromTasks)) || null;
if (completion !== null) {
if (completion < Gantt.ComplectionMin) {
completion = Gantt.ComplectionMin;
}
if (completion > Gantt.ComplectionMax) {
completion = Gantt.ComplectionMax;
}
}
}
});
}
const selectionId: powerbi.extensibility.ISelectionId = selectionBuilder.createSelectionId();
const extraInformation: ExtraInformation[] = [];
const resource: string = (values.Resource && values.Resource[index] as string) || "";
const parent: string = (values.Parent && values.Parent[index] as string) || null;
const Milestone: string = (values.Milestones && !_.isEmpty(values.Milestones[index]) && values.Milestones[index]) || null;
const startDate: Date = (values.StartDate && values.StartDate[index]
&& isValidDate(new Date(values.StartDate[index])) && new Date(values.StartDate[index]))
|| new Date(Date.now());
if (values.ExtraInformation) {
const extraInformationKeys: any[] = Object.keys(values.ExtraInformation);
for (const key of extraInformationKeys) {
const value: string = values.ExtraInformation[key][index];
if (value) {
extraInformation.push({
displayName: key,
value: value
});
}
}
}
const task: Task = {
color,
completion,
resource,
index: null,
name: categoryValue as string,
start: startDate,
end: endDate,
parent,
children: null,
visibility: true,
duration,
taskType: taskType && taskType.name,
description: categoryValue as string,
tooltipInfo: tooltips,
selected: false,
identity: selectionId,
extraInformation,
daysOffList: [],
wasDowngradeDurationUnit,
stepDurationTransformation,
Milestones: Milestone && startDate ? [{ type: Milestone, start: startDate, tooltipInfo: null, category: categoryValue as string }] : []
};
if (parent) {
let parentTask: Task = null;
if (addedParents.indexOf(parent) === -1) {
addedParents.push(parent);
parentTask = {
index: 0,
name: parent,
start: null,
duration: null,
completion: null,
resource: null,
end: null,
parent: null,
children: [task],
visibility: true,
taskType: null,
description: null,
color: null,
tooltipInfo: null,
extraInformation: _.includes(collapsedTasks, parent) ? extraInformation : null,
daysOffList: null,
wasDowngradeDurationUnit: null,
selected: null,
identity: selectionBuilder.createSelectionId(),
Milestones: Milestone && startDate ? [{ type: Milestone, start: startDate, tooltipInfo: null, category: categoryValue as string }] : []
};
tasks.push(parentTask);
} else {
parentTask = tasks.filter(x => x.index === 0 && x.name === parent)[0];
parentTask.children.push(task);
}
}
tasks.push(task);
});
Gantt.downgradeDurationUnitIfNeeded(tasks, durationUnit);
if (values.Parent) {
tasks = Gantt.sortTasksWithParents(tasks, sortingOptions);
}
tasks.forEach(task => {
if (task.children && task.children.length) {
return;
}
if (task.end && task.start && isValidDate(task.end)) {
const durationInMilliseconds: number = task.end.getTime() - task.start.getTime(),
minDurationUnitInMilliseconds: number = Gantt.getMinDurationUnitInMilliseconds(durationUnit);
task.end = durationInMilliseconds < minDurationUnitInMilliseconds ? Gantt.getEndDate(durationUnit, task.start, task.duration) : task.end;
} else {
task.end = isValidDate(task.end) ? task.end : Gantt.getEndDate(durationUnit, task.start, task.duration);
}
if (settings.daysOff.show && duration) {
let datesDiff: number = 0;
do {
task.daysOffList = Gantt.calculateDaysOff(
+settings.daysOff.firstDayOfWeek,
new Date(task.start.getTime()),
new Date(task.end.getTime())
);
if (task.daysOffList.length) {
const isDurationFilled: boolean = _.findIndex(dataView.metadata.columns, col => col.roles.hasOwnProperty(GanttRoles.Duration)) !== -1;
if (isDurationFilled) {
let extraDuration = Gantt.calculateExtraDurationDaysOff(task.daysOffList, task.start, task.end, +settings.daysOff.firstDayOfWeek, durationUnit);
task.end = Gantt.getEndDate(durationUnit, task.start, task.duration + extraDuration);
}
const lastDayOffListItem = task.daysOffList[task.daysOffList.length - 1];
const lastDayOff: Date = lastDayOffListItem[1] === 1 ? lastDayOffListItem[0]
: new Date(lastDayOffListItem[0].getFullYear(), lastDayOffListItem[0].getMonth(), lastDayOffListItem[0].getDate() + 1);
datesDiff = Math.ceil((task.end.getTime() - lastDayOff.getTime()) / MillisecondsInADay);
}
} while (task.daysOffList.length && datesDiff - DaysInAWeekend > DaysInAWeek);
}
if (task.parent) {
task.visibility = collapsedTasks.indexOf(task.parent) === -1;
}
});
tasks.forEach((task: Task) => {
if (!task.children || _.includes(collapsedTasks, task.name)) {
task.tooltipInfo = Gantt.getTooltipInfo(task, formatters, durationUnit, localizationManager, isEndDateFillled);
if (task.Milestones) {
task.Milestones.forEach((milestone) => {
const dateFormatted = formatters.startDateFormatter.format(task.start);
const dateTypesSettings = settings.dateType;
milestone.tooltipInfo = Gantt.getTooltipForMilestoneLine(dateFormatted, localizationManager, dateTypesSettings, [milestone.type], [milestone.category]);
});
}
}
});
return tasks;
}