diff --git a/src/app/gantt/interval-planning/interval-planning.component.html b/src/app/gantt/interval-planning/interval-planning.component.html new file mode 100644 index 0000000..1de9a43 --- /dev/null +++ b/src/app/gantt/interval-planning/interval-planning.component.html @@ -0,0 +1,36 @@ +
+
+ @for(item of view.cellDescriptors; track item.title) { +
+
+
+
+ @for (item of view.tickDescriptors; track item.title) { + {{item.title}} + } +
+
+
+
+ } +
+ + @for (day of weekdays; track day) { +
{{formatDayName(day)}} +
+
+ + @for (time of view.tickDescriptors; track time.title; let index = $index) { +
+
+ } + @for (interval of intervalSet[day]; track interval) { +
+
+
+
+ } +
+ } +
\ No newline at end of file diff --git a/src/app/gantt/interval-planning/interval-planning.component.scss b/src/app/gantt/interval-planning/interval-planning.component.scss new file mode 100644 index 0000000..52a2c0b --- /dev/null +++ b/src/app/gantt/interval-planning/interval-planning.component.scss @@ -0,0 +1,104 @@ +.container { + position: relative; + width: 100%; + background-color: #ccc; + + display: grid; + grid-template-columns: max-content 1fr; + + --bar-margin: 5px; + --row-height: 1.5rem; + + --header-height: 4rem; + + --bg-color: rgb(247, 247, 247); //#fafafa; + --separator-color: rgb(238, 238, 238); + --bg-weekend-color: #e7dada; + --bg-open-color: #fff; + --bg-closed-color: rgb(208, 208, 208); + + --bg-week-color-even: #98afc7; + --bg-week-color-odd: #8391a1; + + background-color: var(--bg-color); + + border: solid thin black; + box-sizing: border-box; + + .time-head { + grid-column: 2; + + .ticks { + display: flex; + color: #000; + + :first-child { + border-left: none; + } + + .tick { + padding-left: 0.2rem; + box-sizing: border-box; + font-size: 0.7rem; + border-right: solid thin #fff; + border-color: #000; + } + } + } + + .weekday { + height: calc(var(--row-height) + 2 * var(--bar-margin)); + display: flex; + align-items: center; + justify-content: flex-end; + + padding: 0 0.5rem; + border-bottom: solid thin var(--separator-color); + + &.weekend { + background-color: var(--bg-weekend-color); + } + + &.sunday { + background-color: var(--bg-weekend-color); + color: red; + } + } + + .bar-row { + position: relative; + + height: calc(var(--row-height) + 2 * var(--bar-margin)); + border-color: var(--separator-color); + background-color: var(--bg-closed-color); + + border-bottom: solid thin var(--separator-color); + + .hour-separator { + position: absolute; + height: 100%; + border-left: solid thin var(--separator-color); + } + + .interval { + position: absolute; + z-index: 99; + height: calc(var(--row-height) + 2 * var(--bar-margin)); + background-color: #fff; + + display: flex; + justify-content: space-between; + + .resize-action { + width: 4px; + height: 100%; + background-color: red; + + &:hover, + &:active { + cursor: ew-resize; + } + } + } + } +} diff --git a/src/app/gantt/interval-planning/interval-planning.component.spec.ts b/src/app/gantt/interval-planning/interval-planning.component.spec.ts new file mode 100644 index 0000000..637f976 --- /dev/null +++ b/src/app/gantt/interval-planning/interval-planning.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { IntervalPlanningComponent } from './interval-planning.component'; + +describe('IntervalPlanningComponent', () => { + let component: IntervalPlanningComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [IntervalPlanningComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(IntervalPlanningComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/gantt/interval-planning/interval-planning.component.ts b/src/app/gantt/interval-planning/interval-planning.component.ts new file mode 100644 index 0000000..01c8455 --- /dev/null +++ b/src/app/gantt/interval-planning/interval-planning.component.ts @@ -0,0 +1,83 @@ +import { ChangeDetectorRef, Component, ElementRef, HostListener, ViewChild } from '@angular/core'; +import { GanttView } from '../views/view'; +import { Observable } from 'rxjs'; +import { WeekdayNumbers } from 'luxon'; +import { _VisuallyHiddenLoader } from "@angular/cdk/private"; + +interface IntervalSet { + [key: number]: IntervalProperties[], +} + +interface IntervalProperties { + start: number, + duration: number, +} + +@Component({ + selector: 'app-interval-planning', + imports: [], + templateUrl: './interval-planning.component.html', + styleUrl: './interval-planning.component.scss' +}) +export class IntervalPlanningComponent { + @ViewChild('barContainer') _barContainer!: ElementRef; + + @HostListener('window:mousemove', ['$event']) + onMouseMove(event: MouseEvent) { + this.mouse = { x: event.clientX, y: event.clientY }; + + if (this.resizing) this.resize(); + } + @HostListener('window:mouseup', ['$event']) + onMouseUp(event: MouseEvent) { + this.resizing = null; + } + + mouse = { x: 0, y: 0 }; + resizing: IntervalProperties | null = null; + + view: GanttView; + + globalBaseFontSize: number = 16; + barContainerWidth: number = 0; + + weekdays: WeekdayNumbers[] = [1, 2, 3, 4, 5, 6, 7]; + intervalSet: IntervalSet = { 2: [{ start: 3600, duration: 3600 }] } + + constructor(private changeDetectorRef: ChangeDetectorRef) { + this.view = new GanttView(); + this.view.changeView('day') + } + + ngAfterViewInit(): void { + // get base font size + let fontSize = window.getComputedStyle(this._barContainer.nativeElement).getPropertyValue('font-size'); + this.globalBaseFontSize = parseInt(fontSize.slice(0, fontSize.length - 2)); + this.view.globalBaseFontSize = parseInt(fontSize.slice(0, fontSize.length - 2)); + + // observe resizing of the bar container + new Observable((observer) => { + const resizeObserver = new ResizeObserver(() => { + observer.next(); + }); + resizeObserver.observe(this._barContainer.nativeElement); + }).subscribe((change) => { + console.log(this._barContainer.nativeElement.offsetWidth) + this.barContainerWidth = this._barContainer.nativeElement.offsetWidth; + this.view.width = this._barContainer.nativeElement.offsetWidth; + + this.changeDetectorRef.detectChanges(); + }); + } + + formatDayName(day: WeekdayNumbers): string { + return this.view.viewType.start.set({ weekday: day }).toFormat('EEEE') + } + + resize(): void { + // if (this.resizeCondMeet()) { + if (this.resizing) + this.resizing.duration += this.mouse.x; + // } + } +}