diff --git a/frontend/app/components/wp-table/timeline/cell-renderer/timeline-cell-renderer.ts b/frontend/app/components/wp-table/timeline/cell-renderer/timeline-cell-renderer.ts index b2ea395acf..6815f536ff 100644 --- a/frontend/app/components/wp-table/timeline/cell-renderer/timeline-cell-renderer.ts +++ b/frontend/app/components/wp-table/timeline/cell-renderer/timeline-cell-renderer.ts @@ -1,5 +1,8 @@ import {WorkPackageResourceInterface} from "../../../api/api-v3/hal-resources/work-package-resource.service"; -import {RenderInfo, calculatePositionValueForDayCount, timelineElementCssClass} from "../wp-timeline"; +import { + RenderInfo, calculatePositionValueForDayCount, timelineElementCssClass, + calculatePositionValueForDayCountinPx +} from "../wp-timeline"; import {classNameLeftHandle, classNameRightHandle} from "../wp-timeline-cell-mouse-handler"; import * as moment from 'moment'; import Moment = moment.Moment; @@ -223,6 +226,17 @@ export class TimelineCellRenderer { return true; } + getRightmostPosition(renderInfo: RenderInfo): number { + const wp = renderInfo.workPackage; + + let start = moment(wp.startDate as any); + let due = moment(wp.dueDate as any); + const offsetStart = start.diff(renderInfo.viewParams.dateDisplayStart, "days"); + const duration = due.diff(start, "days") + 1; + + return calculatePositionValueForDayCountinPx(renderInfo.viewParams, offsetStart + duration); + } + /** * Render the generic cell element, a bar spanning from * start to due date. diff --git a/frontend/app/components/wp-table/timeline/wp-timeline-cell.ts b/frontend/app/components/wp-table/timeline/wp-timeline-cell.ts index f59128a0f9..8549e5cd25 100644 --- a/frontend/app/components/wp-table/timeline/wp-timeline-cell.ts +++ b/frontend/app/components/wp-table/timeline/wp-timeline-cell.ts @@ -47,7 +47,7 @@ export class WorkPackageTimelineCell { private subscription: Subscription; - private latestRenderInfo: RenderInfo; + public latestRenderInfo: RenderInfo; private wpElement: HTMLDivElement|null = null; @@ -57,21 +57,28 @@ export class WorkPackageTimelineCell { private wpCacheService: WorkPackageCacheService, private states: States, private workPackageId: string, - private timelineCell: HTMLElement) { + public timelineCell: HTMLElement) { } activate() { this.subscription = this.workPackageTimeline.addWorkPackage(this.workPackageId) .subscribe(renderInfo => { this.updateView(renderInfo); + this.workPackageTimeline.globalService.updateWorkPackageInfo(this); }); } deactivate() { this.clear(); + this.workPackageTimeline.globalService.removeWorkPackageInfo(this.workPackageId); this.subscription && this.subscription.unsubscribe(); } + getRightmostPosition(): number { + const renderer = this.cellRenderer(this.latestRenderInfo.workPackage); + return renderer.getRightmostPosition(this.latestRenderInfo); + } + private clear() { this.timelineCell.innerHTML = ""; this.wpElement = null; @@ -136,6 +143,8 @@ export class WorkPackageTimelineCell { } private updateView(renderInfo: RenderInfo) { + // console.log("updateView()", "wpID=" + renderInfo.workPackage.id); + this.latestRenderInfo = renderInfo; const renderer = this.cellRenderer(renderInfo.workPackage); @@ -148,4 +157,5 @@ export class WorkPackageTimelineCell { this.clear(); } } + } diff --git a/frontend/app/components/wp-table/timeline/wp-timeline-container.directive.ts b/frontend/app/components/wp-table/timeline/wp-timeline-container.directive.ts index dd65107bbb..3d338e1bbe 100644 --- a/frontend/app/components/wp-table/timeline/wp-timeline-container.directive.ts +++ b/frontend/app/components/wp-table/timeline/wp-timeline-container.directive.ts @@ -32,11 +32,11 @@ import {InteractiveTableController} from "./../../common/interactive-table/inter import {WpTimelineHeader} from "./wp-timeline.header"; import {States} from "./../../states.service"; import {BehaviorSubject, Observable} from "rxjs"; - -import * as moment from 'moment'; +import * as moment from "moment"; import Moment = moment.Moment; import IDirective = angular.IDirective; import IScope = angular.IScope; +import {WpTimelineGlobalService} from "./wp-timeline-global.directive"; export class WorkPackageTimelineTableController { @@ -46,6 +46,8 @@ export class WorkPackageTimelineTableController { public wpTimelineHeader: WpTimelineHeader; + public readonly globalService = new WpTimelineGlobalService(); + private updateAllWorkPackagesSubject = new BehaviorSubject(true); private refreshViewRequested = false; @@ -120,6 +122,7 @@ export class WorkPackageTimelineTableController { const viewParamsChanged = this.calculateViewParams(this._viewParameters); if (viewParamsChanged) { // view params have changed, notify all cells + // console.log("addWorkPackage()", wp.id, "viewParamsChanged==true"); this.refreshView(); } @@ -150,6 +153,7 @@ export class WorkPackageTimelineTableController { // Calculate view parameters for (const wpId in this.workPackagesInView) { + // console.log(" check", wpId); const workPackage = this.workPackagesInView[wpId]; const startDate = workPackage.startDate ? moment(workPackage.startDate) : currentParams.now; @@ -185,12 +189,14 @@ export class WorkPackageTimelineTableController { // start date if (!newParams.dateDisplayStart.isSame(this._viewParameters.dateDisplayStart)) { changed = true; + // console.log(" start changed"); this._viewParameters.dateDisplayStart = newParams.dateDisplayStart; } // end date if (!newParams.dateDisplayEnd.isSame(this._viewParameters.dateDisplayEnd)) { changed = true; + // console.log(" end changed"); this._viewParameters.dateDisplayEnd = newParams.dateDisplayEnd; } @@ -209,6 +215,6 @@ function wpTimelineContainer() { controller: WorkPackageTimelineTableController, bindToController: true }; -}; +} openprojectModule.directive('wpTimelineContainer', wpTimelineContainer); diff --git a/frontend/app/components/wp-table/timeline/wp-timeline-global.directive.ts b/frontend/app/components/wp-table/timeline/wp-timeline-global.directive.ts index cfefdd97de..674a6e40d7 100644 --- a/frontend/app/components/wp-table/timeline/wp-timeline-global.directive.ts +++ b/frontend/app/components/wp-table/timeline/wp-timeline-global.directive.ts @@ -25,38 +25,104 @@ // // See doc/COPYRIGHT.rdoc for more details. // ++ -import {wpDirectivesModule} from "../../../angular-modules"; -import {WorkPackageTimelineTableController} from "./wp-timeline-container.directive"; import IDirective = angular.IDirective; import IComponentOptions = angular.IComponentOptions; +import {WorkPackageResourceInterface} from "../../api/api-v3/hal-resources/work-package-resource.service"; +import {RenderInfo, TimelineViewParameters, timelineElementCssClass} from "./wp-timeline"; +import {WorkPackageTimelineCell} from "./wp-timeline-cell"; -class WpTimelineGlobalController { +export const timelineGlobalElementCssClassname = "timeline-global-element"; - wpTimelineContainer: WorkPackageTimelineTableController; - init() { - console.log("init"); - console.log(this.wpTimelineContainer); +export class TimelineGlobalElement { + from: string; + to: string; +} + +export class WpTimelineGlobalService { + + private workPackageIdOrder: string[] = ["56", "55", "54"]; + + private cells: {[id: string]: WorkPackageTimelineCell} = {}; + + private elements: TimelineGlobalElement[] = []; + + constructor() { + setTimeout(() => { + console.log("displayRelation"); + this.displayRelation("55", "54"); + }, 3000); } + updateWorkPackageInfo(cell: WorkPackageTimelineCell) { + this.cells[cell.latestRenderInfo.workPackage.id] = cell; + // TODO called to often -} + this.update(); + } + + removeWorkPackageInfo(id: string) { + delete this.cells[id]; + this.update() + } + + displayRelation(from: string, to: string) { + const elem = new TimelineGlobalElement(); + elem.from = from; + elem.to = to; + this.elements.push(elem); + this.update(); + } + + private update() { + this.removeAllElements(); + this.renderElements(); + } + + private removeAllElements() { + // console.log("removeAllElements()"); + jQuery("." + timelineGlobalElementCssClassname).children().remove(); + } + + private renderElements() { + console.debug("renderElements()"); + + for (let e of this.elements) { + + const idxFrom = this.workPackageIdOrder.indexOf(e.from); + const idxTo = this.workPackageIdOrder.indexOf(e.to); + const start = Math.min(idxFrom, idxTo); + const end = Math.max(idxFrom, idxTo); + + // start + const startCell = this.cells[e.from]; + let lastX = startCell.getRightmostPosition(); + + const line = document.createElement("div"); + line.className = timelineElementCssClass; + line.style.position = "absolute"; + line.style.zIndex = "100"; + line.style.cssFloat = "left"; + line.style.backgroundColor = "green"; + line.style.top = "19px"; + line.style.left = lastX + "px"; + line.style.width = "20px"; + lastX += 20; + line.style.height = "2px"; + startCell.timelineCell.appendChild(line); + + // vert line + for (let index = start; index <= end; index++) { + const id = this.workPackageIdOrder[index]; + const cell = this.cells[id]; + + // console.log("i", index, id, cell); + } + } + + } -function directive(): IDirective { - return { - require: ["^^wpTimelineContainer", "^wpTimelineGlobal"], - link: (scope, - element, - attrs, - [a, b]: [WorkPackageTimelineTableController, WpTimelineGlobalController]) => { - b.wpTimelineContainer = a; - b.init(); - }, - controller: WpTimelineGlobalController - }; } -wpDirectivesModule - .directive('wpTimelineGlobal', directive); diff --git a/frontend/app/components/wp-table/timeline/wp-timeline.ts b/frontend/app/components/wp-table/timeline/wp-timeline.ts index 9ded358e0f..1a3a9afd03 100644 --- a/frontend/app/components/wp-table/timeline/wp-timeline.ts +++ b/frontend/app/components/wp-table/timeline/wp-timeline.ts @@ -25,12 +25,11 @@ // // See doc/COPYRIGHT.rdoc for more details. // ++ - -import * as moment from 'moment'; +import * as moment from "moment"; +import {WorkPackageResourceInterface} from "../../api/api-v3/hal-resources/work-package-resource.service"; +import {WpTimelineHeader} from "./wp-timeline.header"; import Moment = moment.Moment; -import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service'; -import {WpTimelineHeader} from "./wp-timeline.header"; export const timelineElementCssClass = "timeline-element"; /** @@ -38,7 +37,7 @@ export const timelineElementCssClass = "timeline-element"; */ export class TimelineViewParametersSettings { - showDurationInPx = true; + // showDurationInPx = true; scrollOffsetInDays = 0; @@ -105,17 +104,22 @@ export interface RenderInfo { /** * - * @param viewParams - * @param days - * @returns {string} */ -export function calculatePositionValueForDayCount(viewParams: TimelineViewParameters, days: number): string { +export function calculatePositionValueForDayCountinPx(viewParams: TimelineViewParameters, days: number): number { const daysInPx = days * viewParams.pixelPerDay; - if (viewParams.settings.showDurationInPx) { - return daysInPx + "px"; - } else { - return (daysInPx / viewParams.maxWidthInPx * 100) + "%"; - } + return daysInPx; +} + +/** + * + */ +export function calculatePositionValueForDayCount(viewParams: TimelineViewParameters, days: number): string { + const value = calculatePositionValueForDayCountinPx(viewParams, days); + // if (viewParams.settings.showDurationInPx) { + return value + "px"; + // } else { + // return (value / viewParams.maxWidthInPx * 100) + "%"; + // } } diff --git a/frontend/app/components/wp-table/wp-table.directive.html b/frontend/app/components/wp-table/wp-table.directive.html index 4caf9ddab6..d836afe911 100644 --- a/frontend/app/components/wp-table/wp-table.directive.html +++ b/frontend/app/components/wp-table/wp-table.directive.html @@ -53,6 +53,24 @@ + + + + + + + + + + + + + + + + + +