devexpress-gantt
Version:
DevExpress Gantt Control
176 lines (152 loc) • 7.87 kB
text/typescript
import { Size } from "@devexpress/utils/lib/geometry/size";
import { Dependency } from "../../Model/Entities/Dependency";
import { Resource } from "../../Model/Entities/Resource";
import { Task } from "../../Model/Entities/Task";
import { ViewVisualModelItem } from "../../Model/VisualModel/ViewVisualModelItem";
import { TaskTitlePosition } from "../Helpers/Enums";
import { GridElementInfo } from "../Helpers/GridElementInfo";
import { GridLayoutCalculator } from "../Helpers/GridLayoutCalculator";
import { RenderElementUtils } from "./RenderElementUtils";
import { RenderHelper } from "./RenderHelper";
import { TaskRender } from "./TaskRender";
export class CustomTaskRender {
private _renderHelper: RenderHelper;
private _taskRender: TaskRender;
private _pendingTemplateFuncsToRender: Record<number, Array<(container: HTMLElement, model: any, ...args) => void>> = [];
constructor(renderHelepr: RenderHelper, taskRender: TaskRender) {
this._renderHelper = renderHelepr;
this._taskRender = taskRender;
}
protected get gridLayoutCalculator(): GridLayoutCalculator {
return this._renderHelper.gridLayoutCalculator;
}
protected get tickSize(): Size {
return this._renderHelper.tickSize;
}
protected get taskTitlePosition(): TaskTitlePosition {
return this._renderHelper.taskTitlePosition;
}
protected get taskElements(): HTMLElement[] {
return this._taskRender.taskElements;
}
protected get taskArea(): HTMLElement {
return this._renderHelper.taskArea;
}
getViewItem(index: number): ViewVisualModelItem {
return this._renderHelper.getViewItem(index);
}
getTask(index: number): Task {
return this._renderHelper.getTask(index);
}
destroyTemplate(container: HTMLElement): void {
this._renderHelper.destroyTemplate(container);
}
getTaskDependencies(taskInternalId: any): Dependency[] {
return this._renderHelper.getTaskDependencies(taskInternalId);
}
getTaskResources(key: any): Resource[] {
return this._renderHelper.getTaskResources(key);
}
attachEventsOnTask(taskIndex: number): void {
this._renderHelper.attachEventsOnTask(taskIndex);
}
recreateConnectorLineElement(dependencyId: string, forceRender: boolean = false): void {
this._renderHelper.recreateConnectorLineElement(dependencyId, forceRender);
}
createTaskSelectionElement(taskIndex: number): void {
this._taskRender.createTaskSelectionElement(taskIndex);
}
createCustomTaskElement(index: number, taskTemplateFunction: (container: HTMLElement, model: any, ...args) => void): void {
this._saveTemplateFuncToStack(index, taskTemplateFunction);
if(this._hasRepeatedTemplateRenderCall(index))
return;
const viewItem = this.getViewItem(index);
if(viewItem) {
viewItem.isCustom = false;
const taskTemplateContainer = document.createElement("DIV");
const taskInformation = this.createCustomTaskInformation(index);
viewItem.isCustom = true;
taskTemplateFunction(taskTemplateContainer, taskInformation, this.onTaskTemplateContainerRendered.bind(this), index);
}
this._clearTemplateFuncsStack(index);
}
onTaskTemplateContainerRendered(taskTemplateContainer: HTMLElement, taskIndex: number): void {
if(this._hasRepeatedTemplateRenderCall(taskIndex)) {
if(taskTemplateContainer)
this._renderHelper.destroyTemplate(taskTemplateContainer as HTMLElement);
const templateFunc = this._getLastPendingTemplateFunc(taskIndex);
setTimeout(() => this.createCustomTaskElement(taskIndex, templateFunc));
}
else
this.drawCustomTask(taskTemplateContainer, taskIndex);
this._clearTemplateFuncsStack(taskIndex);
}
_saveTemplateFuncToStack(index: number, taskTemplateFunction: (container: HTMLElement, model: any, ...args) => void): void {
this._pendingTemplateFuncsToRender[index] ??= [];
this._pendingTemplateFuncsToRender[index].push(taskTemplateFunction);
}
_clearTemplateFuncsStack(index: number): void { this._pendingTemplateFuncsToRender[index] = []; }
_hasRepeatedTemplateRenderCall(index: number): boolean { return this._pendingTemplateFuncsToRender[index].length > 1; }
_getLastPendingTemplateFunc(index: number): (container: HTMLElement, model: any, ...args) => void {
const pendingStack = this._pendingTemplateFuncsToRender[index];
return pendingStack[pendingStack.length - 1];
}
createCustomTaskWrapperElement(index: number, taskWrapperInfo: GridElementInfo): void {
RenderElementUtils.create(taskWrapperInfo, index, this.taskArea, this.taskElements);
}
createCustomTaskVisualElement(index: number, taskElementInfo: GridElementInfo): HTMLElement {
const taskElement = RenderElementUtils.create(taskElementInfo, index, this.taskElements[index]);
return taskElement;
}
drawCustomTask(taskTemplateContainer: HTMLElement, taskIndex: number):void {
const viewItem = this.getViewItem(taskIndex);
if(!viewItem || !this.taskElements[taskIndex])
return;
viewItem.visible = !!taskTemplateContainer.innerHTML;
this.taskElements[taskIndex].innerHTML = taskTemplateContainer.innerHTML;
viewItem.size.height = this.taskElements[taskIndex].offsetHeight;
viewItem.size.width = this.taskElements[taskIndex].offsetWidth;
this.destroyTemplate(this.taskElements[taskIndex]);
this._taskRender.removeTaskElement(taskIndex);
if(viewItem.visible && viewItem.task.isValid()) {
const taskWrapperInfo = this.gridLayoutCalculator.getTaskWrapperElementInfo(taskIndex);
this.createCustomTaskWrapperElement(taskIndex, taskWrapperInfo);
this.taskElements[taskIndex].appendChild(taskTemplateContainer);
this.attachEventsOnTask(taskIndex);
}
else {
const taskDependencies = this.getTaskDependencies(viewItem.task.internalId);
if(taskDependencies.length) {
this._taskRender.addInvalidTaskDependencies(taskDependencies);
taskDependencies.forEach(d => this.recreateConnectorLineElement(d.internalId, true));
}
}
if(this._taskRender.isHighlightRowElementAllowed(taskIndex))
this._taskRender.createHighlightRowElement(taskIndex);
if(viewItem.selected)
this.createTaskSelectionElement(taskIndex);
}
createCustomTaskInformation(index: number):any {
const task = this.getTask(index);
const viewItem = this.getViewItem(index);
const taskWrapperInfo = this.gridLayoutCalculator.getTaskWrapperElementInfo(index);
const taskElementInfo = this.gridLayoutCalculator.getTaskElementInfo(index, this.taskTitlePosition !== TaskTitlePosition.Inside);
this.createCustomTaskWrapperElement(index, taskWrapperInfo);
const taskParent = this.taskElements[index];
if(this._renderHelper.taskTitlePosition === TaskTitlePosition.Outside)
this._taskRender.createTaskTextElement(index, taskParent);
this.createCustomTaskVisualElement(index, taskElementInfo);
const taskResources = this.getTaskResources(task.id);
const taskInformation = {
cellSize: this.tickSize,
isMilestone: task.isMilestone(),
isParent: !!viewItem?.children.length,
taskData: task,
taskHTML: taskParent.children,
taskPosition: taskWrapperInfo.position,
taskResources: taskResources,
taskSize: taskElementInfo.size,
};
return taskInformation;
}
}