UNPKG

angular-calendar-timeline

Version:

A timeline for angular that shows events on a timeline board in different modes: days, weeks, and months.

415 lines 74.3 kB
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, HostListener, Inject, Input, Output, PLATFORM_ID, } from '@angular/core'; import { interval, Subject, takeUntil } from 'rxjs'; import { startWith } from 'rxjs/operators'; import { isPlatformBrowser } from "@angular/common"; import { MillisecondsToTime } from "./helpers/date-helpers"; import { ItemsIterator } from "./items-iterator/items-iterator"; import { ZoomsHandler } from "./zooms-handler/zooms-handler"; import { DefaultZooms } from "./zooms-handler/zooms"; import { RowDeterminant } from "./helpers/row-determinant"; import * as i0 from "@angular/core"; import * as i1 from "./strategy-manager"; import * as i2 from "@angular/common"; import * as i3 from "./components/item/timeline-item.component"; import * as i4 from "./components/date-marker/timeline-date-marker.component"; import * as i5 from "./components/scale-header/timeline-scale-header.component"; import * as i6 from "./components/panel/timeline-panel.component"; export class TimelineComponent { /** * Register array of custom zooms. * Current zoom can be changed to any existed in this array by calling method "changeZoom()" */ set zooms(value) { this.zoomsHandler.setZooms(value); } /** * The items of timeline. */ set items(items) { this.itemsIterator.setItems(items); this.redraw(); } /** * Visible timeline width (container visible width - panel width = timeline visible width). */ get visibleScaleWidth() { return this._elementRef.nativeElement.clientWidth - this.panelWidth; } /** * Active zoom. */ get zoom() { return this.zoomsHandler.activeZoom; } /** * Registered zooms list. */ get zooms() { return this.zoomsHandler.zooms; } constructor(_cdr, _strategyManager, _elementRef, _platformId) { this._cdr = _cdr; this._strategyManager = _strategyManager; this._elementRef = _elementRef; this._platformId = _platformId; /** * Indicates the current shown date in the middle of user`s screen. */ this.currentDate = new Date(); this.dateMarkerLeftPosition = 0; this.itemsIterator = new ItemsIterator(); this.zoomsHandler = new ZoomsHandler(DefaultZooms); this._ignoreNextScrollEvent = false; this._destroy$ = new Subject(); /** * Emits event when startDate and endDate of some item was changed by resizing/moving it. */ this.itemTimeChanged = new EventEmitter(); /** * Emits event when item was moved by Y axis. */ this.itemRowChanged = new EventEmitter(); /** * Emits event when current zoom was changed. */ this.zoomChanged = new EventEmitter(); /** * Emits event when user clicked somewhere on time grid. */ this.timeGridClicked = new EventEmitter(); /** * The locale used to format dates. By default is 'en' */ this.locale = 'en'; /** * Height of the each row in pixels. By default is 40. */ this.rowHeight = 40; /** * Height of the each timeline item in pixels. Can't be bigger then 'rowHeight' property. By default is 30. */ this.itemHeight = 30; /** * Height of top dates panel in pixels. By default is 60. */ this.headerHeight = 60; /** * The label of left panel. By default is empty. */ this.panelLabel = ''; /** * Width of left panel in pixels. By default is 160. */ this.panelWidth = 160; /** * Minimal width of left panel in pixels. By default is 50. */ this.minPanelWidth = 50; /** * Maximal width of left panel in pixels. By default is 400. */ this.maxPanelWidth = 400; /** * Sets the left displacement in pixels between parent and child groups in left panel. By default is 15. */ this.offsetForChildPanelItem = 15; /** * Can resize panel. By default is true. */ this.isPanelResizable = true; /** * If false then date marker will be not visible. */ this.showDateMarket = true; this._setStrategies(this.zoom); } ngAfterViewInit() { this.zoomsHandler.activeZoom$ .pipe(takeUntil(this._destroy$)) .subscribe((zoom) => { this._setStrategies(zoom); this.redraw(); this.zoomChanged.emit(zoom); }); if (isPlatformBrowser(this._platformId)) { interval(MillisecondsToTime.Minute) .pipe(startWith(''), takeUntil(this._destroy$)) .subscribe(() => this._recalculateDateMarkerPosition()); } } /** * Recalculate and update view. */ redraw() { this._generateScale(); this._updateItemsPosition(); this.itemsIterator.setItems([...this.itemsIterator.items]); this._recalculateDateMarkerPosition(); this._ignoreNextScrollEvent = true; this._cdr.detectChanges(); this.attachCameraToDate(this.currentDate); } /** * Set horizontal scroll in the middle of the date */ attachCameraToDate(date) { this.currentDate = date; const duration = this.viewModeAdaptor.getDurationInColumns(this.scale.startDate, date); const scrollLeft = (duration * this.zoom.columnWidth) - (this.visibleScaleWidth / 2); this._ignoreNextScrollEvent = true; if (this._elementRef.nativeElement) { this._elementRef.nativeElement.scrollLeft = scrollLeft < 0 ? 0 : scrollLeft; } } /** * Automatically chooses the most optimal zoom and sets horizontal scroll to the center of the items. * Padding sets minimal spacing from left and right to the first and last items. */ fitToContent(paddings) { const firstItem = this.itemsIterator.getFirstItem(true); const lastItem = this.itemsIterator.getLastItem(true); if (!firstItem || !lastItem) return; const startDate = new Date(firstItem.startDate); const endDate = new Date(lastItem.endDate); const zoom = this._calculateOptimalZoom(startDate, endDate, paddings); const viewModeAdaptor = this._strategyManager.getViewModeAdaptor(zoom.viewMode); this.currentDate = new Date(viewModeAdaptor.getMiddleDate(startDate, endDate)); if (this.zoomsHandler.isZoomActive(zoom)) { this.attachCameraToDate(this.currentDate); } else { this.changeZoom(zoom); } } /** * Change zoom to one of the existed */ changeZoom(zoom) { this.zoomsHandler.changeActiveZoom(zoom); } /** * Find zoom by its index and change */ changeZoomByIndex(index) { const zoom = this.zoomsHandler.zooms.find(zoom => zoom.index === index); if (zoom) { this.zoomsHandler.changeActiveZoom(zoom); } else { console.error(`Cannot find zoom with index ${index}`); } } /** * Changes zoom to the max value */ zoomFullIn() { this.zoomsHandler.changeActiveZoom(this.zoomsHandler.getLastZoom()); } /** * Changes zoom to the min value */ zoomFullOut() { this.zoomsHandler.changeActiveZoom(this.zoomsHandler.getFirstZoom()); } /** * Changes zoom for 1 step back */ zoomIn() { this.zoomsHandler.zoomIn(); } /** * Changes zoom for 1 step forward */ zoomOut() { this.zoomsHandler.zoomOut(); } /** * Accepts the relative coordinates to the timeline container and returns the row and column. */ getCellByCoordinates(x, y) { const rowDeterminant = new RowDeterminant(this.itemsIterator); const rowIndex = Math.floor((y - this.headerHeight) / this.rowHeight); const row = rowDeterminant.getStreamByRowIndex(rowIndex); const columnIndex = Math.floor((x - this.panelWidth) / this.zoom.columnWidth); const column = this.scale.columns[columnIndex]; return { column, row }; } _getCurrentDate() { const currentScrollLeft = this._elementRef.nativeElement.scrollLeft ?? 0; const scrollLeftToCenterScreen = currentScrollLeft + (this.visibleScaleWidth / 2); const columns = Math.round(scrollLeftToCenterScreen / this.zoom.columnWidth); return this.viewModeAdaptor.addColumnToDate(this.scale.startDate, columns); } _onItemMoved(event, item) { if (event.y) { this._onItemMovedVertically(event, item); } if (event.x) { this._onItemMovedHorizontally(event, item); } } _onItemMovedHorizontally(event, item) { const transferColumns = Math.round(event.x / this.zoom.columnWidth); const newStartDate = this.viewModeAdaptor.addColumnToDate(new Date(item.startDate), transferColumns); const newEndDate = this.viewModeAdaptor.addColumnToDate(new Date(item.endDate), transferColumns); this.itemTimeChanged.emit({ item, newStartDate, newEndDate }); } _onItemMovedVertically(event, item) { const rowDeterminant = new RowDeterminant(this.itemsIterator); const rowIndex = rowDeterminant.getRowIndexByItem(item); const transferRows = event.y / this.rowHeight; const newRowIndex = rowIndex + transferRows; if (rowIndex === newRowIndex) return; const oldRow = rowDeterminant.getStreamByRowIndex(rowIndex); const newRow = rowDeterminant.getStreamByRowIndex(newRowIndex); this.itemRowChanged.emit({ item, oldRow, newRow }); } _calculateOptimalZoom(startDate, endDate, paddings = 15) { let possibleZoom = this.zoomsHandler.getFirstZoom(); for (let i = this.zoomsHandler.getLastZoom().index; i >= this.zoomsHandler.getFirstZoom().index; i--) { const currentZoom = this.zoomsHandler.zooms[i]; const viewModeAdaptor = this._strategyManager.getViewModeAdaptor(currentZoom.viewMode); const countOfColumns = viewModeAdaptor.getUniqueColumnsWithinRange(startDate, endDate); if (countOfColumns * currentZoom.columnWidth < (this.visibleScaleWidth - paddings * 2)) { possibleZoom = currentZoom; break; } } return possibleZoom; } _trackById(index, item) { return item.id; } _handleContentClick(event) { const scrollLeft = this._elementRef.nativeElement.scrollLeft; const scrollTop = this._elementRef.nativeElement.scrollTop; const rect = this._elementRef.nativeElement.getBoundingClientRect(); const xClick = event.clientX - rect.left + scrollLeft; const yClick = event.clientY - rect.top + scrollTop; const cell = this.getCellByCoordinates(xClick, yClick); this.timeGridClicked.emit({ originalEvent: event, column: cell.column, row: cell.row }); } _onItemResized(event, item) { const calculateNewDate = (movedPx, oldDate) => { const countOfColumnsMoved = Math.round(movedPx / this.zoom.columnWidth); return this.viewModeAdaptor.addColumnToDate(oldDate, countOfColumnsMoved); }; if (event.edges.left) { const newStartDate = calculateNewDate(event.edges.left, new Date(item.startDate)); const isNewStartDateValid = this.viewModeAdaptor.getBeginningDateOfColumn(newStartDate).getTime() <= new Date(item.endDate).getTime(); if (isNewStartDateValid) { this.itemTimeChanged.emit({ item, newStartDate }); } } else { const newEndDate = calculateNewDate(event.edges.right, new Date(item.endDate)); const isNewEndDateValid = this.viewModeAdaptor.getEndingDateOfColumn(newEndDate).getTime() >= new Date(item.startDate).getTime(); if (isNewEndDateValid) { this.itemTimeChanged.emit({ item, newEndDate }); } } } _onScroll(event) { if (!this._ignoreNextScrollEvent) { this.currentDate = this._getCurrentDate(); } this._ignoreNextScrollEvent = false; } _generateScale() { const scaleStartDate = this.scaleGenerator.getStartDate(this.itemsIterator); const scaleEndDate = this.scaleGenerator.getEndDate(this.itemsIterator); this.scale = this.scaleGenerator.generateScale(scaleStartDate, scaleEndDate); } _updateItemsPosition() { this.itemsIterator.forEach((item) => this._updateItemPosition(item)); } _updateItemPosition(item) { item._width = this._calculateItemWidth(item); item._left = this._calculateItemLeftPosition(item); item.updateView && item.updateView(); } _calculateItemLeftPosition(item) { if (!item.startDate || !item.endDate) return 0; const columnsOffsetFromStart = this.viewModeAdaptor.getUniqueColumnsWithinRange(this.scale.startDate, new Date(item.startDate)) - 1; return columnsOffsetFromStart * this.zoom.columnWidth; } _calculateItemWidth(item) { if (!item.startDate || !item.endDate) return 0; const columnsOccupied = this.viewModeAdaptor.getUniqueColumnsWithinRange(new Date(item.startDate), new Date(item.endDate)); return columnsOccupied * this.zoom.columnWidth; } _recalculateDateMarkerPosition() { const countOfColumns = this.viewModeAdaptor.getDurationInColumns(this.scale.startDate, new Date()); this.dateMarkerLeftPosition = countOfColumns * this.zoom.columnWidth; } _setStrategies(zoom) { this.viewModeAdaptor = this._strategyManager.getViewModeAdaptor(zoom.viewMode); this.scaleGenerator = this._strategyManager.getScaleGenerator(zoom.viewMode); } ngOnDestroy() { this._destroy$.next(); this._destroy$.complete(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.StrategyManager }, { token: ElementRef }, { token: PLATFORM_ID }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimelineComponent, selector: "timeline-calendar", inputs: { locale: "locale", rowHeight: "rowHeight", itemHeight: "itemHeight", headerHeight: "headerHeight", panelLabel: "panelLabel", panelWidth: "panelWidth", minPanelWidth: "minPanelWidth", maxPanelWidth: "maxPanelWidth", offsetForChildPanelItem: "offsetForChildPanelItem", isPanelResizable: "isPanelResizable", showDateMarket: "showDateMarket", panelItemTemplate: "panelItemTemplate", itemContentTemplate: "itemContentTemplate", columnSeparatorTemplate: "columnSeparatorTemplate", dateMarkerTemplate: "dateMarkerTemplate", zooms: "zooms", items: "items" }, outputs: { itemTimeChanged: "itemTimeChanged", itemRowChanged: "itemRowChanged", zoomChanged: "zoomChanged", timeGridClicked: "timeGridClicked" }, host: { listeners: { "scroll": "_onScroll($event)" } }, ngImport: i0, template: "<timeline-panel\r\n (widthChanged)=\"panelWidth = $event\"\r\n [width]=\"panelWidth\"\r\n [maxWidth]=\"maxPanelWidth\"\r\n [minWidth]=\"minPanelWidth\"\r\n [resizable]=\"isPanelResizable\"\r\n [itemTemplate]=\"panelItemTemplate\"\r\n [label]=\"panelLabel\"\r\n [headerHeight]=\"headerHeight\"\r\n [items]=\"itemsIterator.items\"\r\n [locale]=\"locale\"\r\n [childGroupOffset]=\"offsetForChildPanelItem\"\r\n [rowHeight]=\"rowHeight\">\r\n</timeline-panel>\r\n\r\n<div class='content-wrapper' (click)=\"_handleContentClick($event)\">\r\n <timeline-scale-header\r\n [height]=\"headerHeight\"\r\n [formatter]=\"scaleGenerator.formatter\"\r\n [zoom]='zoom'\r\n [scale]='scale'\r\n [locale]=\"locale\"\r\n ></timeline-scale-header>\r\n\r\n <div class=\"column-separators\">\r\n <ng-container *ngFor='let date of scale?.columns; index as i; trackBy: _trackById'>\r\n <div class=\"line\" *ngIf=\"!columnSeparatorTemplate\"\r\n [style.left.px]='zoom.columnWidth * (i + 1)'\r\n [style.height]=\"'calc(100% - ' + headerHeight + 'px)'\">\r\n </div>\r\n\r\n <ng-template [ngTemplateOutlet]=\"columnSeparatorTemplate\"\r\n [ngTemplateOutletContext]=\"{column: date, index: i, columnWidth: zoom.columnWidth, headerHeight: headerHeight}\">\r\n </ng-template>\r\n </ng-container>\r\n </div>\r\n\r\n <timeline-date-marker *ngIf=\"showDateMarket\"\r\n [leftPosition]=\"dateMarkerLeftPosition\"\r\n [headerHeight]=\"headerHeight\"\r\n [scale]=\"scale\"\r\n [customTemplate]=\"dateMarkerTemplate\"\r\n ></timeline-date-marker>\r\n\r\n <div class='timeline-items' *ngIf=\"!itemsIterator.isEmpty()\">\r\n <ng-container *ngFor='let group of itemsIterator.items; trackBy: _trackById;'>\r\n <ng-container *ngIf=\"!group.streamItems\">\r\n <div [style.height.px]='rowHeight' #rowContainer class='item-row'>\r\n <ng-container [ngTemplateOutlet]='itemTemplate'\r\n [ngTemplateOutletContext]='{$implicit: group, rowContainer: rowContainer}'\r\n ></ng-container>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{$implicit: group}'\r\n ></ng-container>\r\n </ng-container>\r\n\r\n <ng-template #itemTemplate let-item let-rowContainer=\"rowContainer\">\r\n <timeline-item [item]='item'\r\n [rowContainer]='rowContainer'\r\n [scale]=\"scale\"\r\n [height]=\"itemHeight\"\r\n [rowHeight]=\"rowHeight\"\r\n [locale]=\"locale\"\r\n (itemResized)=\"_onItemResized($event.event, $event.item)\"\r\n (itemMoved)=\"_onItemMoved($event.event, $event.item)\"\r\n [contentTemplate]='itemContentTemplate'\r\n ></timeline-item>\r\n </ng-template>\r\n\r\n <ng-template #itemsIterationTemplate let-group>\r\n <div *ngFor='let streamLevel of (group._streamLevels || []); trackBy: _trackById;'>\r\n <div [style.height.px]='rowHeight' class='item-row' #rowContainer>\r\n <ng-container *ngFor=\"let item of streamLevel\">\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: item, rowContainer: rowContainer}\"\r\n ></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div [style.height.px]='rowHeight' class='item-row' *ngIf=\"group?._streamLevels?.length === 0\">\r\n </div>\r\n\r\n <ng-container *ngIf='group.childrenItemsExpanded'>\r\n <div *ngFor='let item of (group.childrenItems || []); trackBy: _trackById;'>\r\n <div [style.height.px]='rowHeight' *ngIf=\"!item.streamItems\" class='item-row' #rowContainer>\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: item, rowContainer: rowContainer}\"\r\n ></ng-container>\r\n </div>\r\n\r\n <ng-container [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{$implicit: item}'\r\n ></ng-container>\r\n </div>\r\n </ng-container>\r\n </ng-template>\r\n </div>\r\n</div>\r\n", styles: [":host{height:100%;overflow:auto;display:flex;flex-grow:1;flex-direction:row;font-size:14px;position:relative}.content-wrapper{position:relative;height:fit-content;min-height:100%}.column-separators .line{position:absolute;width:1px;height:100%;background-color:#d0d0d0}.timeline-items{display:flex;flex-direction:column;height:auto}.timeline-items .item-row{display:flex;align-items:center;flex-direction:row;position:relative;z-index:7;box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i3.TimelineItemComponent, selector: "timeline-item", inputs: ["item", "scale", "rowContainer", "height", "rowHeight", "locale", "contentTemplate"], outputs: ["itemResized", "itemMoved"] }, { kind: "component", type: i4.TimelineDateMarkerComponent, selector: "timeline-date-marker", inputs: ["leftPosition", "headerHeight", "customTemplate", "scale"] }, { kind: "component", type: i5.TimelineScaleHeaderComponent, selector: "timeline-scale-header", inputs: ["height", "scale", "formatter", "locale", "zoom"] }, { kind: "component", type: i6.TimelinePanelComponent, selector: "timeline-panel", inputs: ["items", "label", "width", "resizable", "minWidth", "maxWidth", "headerHeight", "rowHeight", "locale", "childGroupOffset", "itemTemplate"], outputs: ["widthChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineComponent, decorators: [{ type: Component, args: [{ selector: 'timeline-calendar', changeDetection: ChangeDetectionStrategy.OnPush, template: "<timeline-panel\r\n (widthChanged)=\"panelWidth = $event\"\r\n [width]=\"panelWidth\"\r\n [maxWidth]=\"maxPanelWidth\"\r\n [minWidth]=\"minPanelWidth\"\r\n [resizable]=\"isPanelResizable\"\r\n [itemTemplate]=\"panelItemTemplate\"\r\n [label]=\"panelLabel\"\r\n [headerHeight]=\"headerHeight\"\r\n [items]=\"itemsIterator.items\"\r\n [locale]=\"locale\"\r\n [childGroupOffset]=\"offsetForChildPanelItem\"\r\n [rowHeight]=\"rowHeight\">\r\n</timeline-panel>\r\n\r\n<div class='content-wrapper' (click)=\"_handleContentClick($event)\">\r\n <timeline-scale-header\r\n [height]=\"headerHeight\"\r\n [formatter]=\"scaleGenerator.formatter\"\r\n [zoom]='zoom'\r\n [scale]='scale'\r\n [locale]=\"locale\"\r\n ></timeline-scale-header>\r\n\r\n <div class=\"column-separators\">\r\n <ng-container *ngFor='let date of scale?.columns; index as i; trackBy: _trackById'>\r\n <div class=\"line\" *ngIf=\"!columnSeparatorTemplate\"\r\n [style.left.px]='zoom.columnWidth * (i + 1)'\r\n [style.height]=\"'calc(100% - ' + headerHeight + 'px)'\">\r\n </div>\r\n\r\n <ng-template [ngTemplateOutlet]=\"columnSeparatorTemplate\"\r\n [ngTemplateOutletContext]=\"{column: date, index: i, columnWidth: zoom.columnWidth, headerHeight: headerHeight}\">\r\n </ng-template>\r\n </ng-container>\r\n </div>\r\n\r\n <timeline-date-marker *ngIf=\"showDateMarket\"\r\n [leftPosition]=\"dateMarkerLeftPosition\"\r\n [headerHeight]=\"headerHeight\"\r\n [scale]=\"scale\"\r\n [customTemplate]=\"dateMarkerTemplate\"\r\n ></timeline-date-marker>\r\n\r\n <div class='timeline-items' *ngIf=\"!itemsIterator.isEmpty()\">\r\n <ng-container *ngFor='let group of itemsIterator.items; trackBy: _trackById;'>\r\n <ng-container *ngIf=\"!group.streamItems\">\r\n <div [style.height.px]='rowHeight' #rowContainer class='item-row'>\r\n <ng-container [ngTemplateOutlet]='itemTemplate'\r\n [ngTemplateOutletContext]='{$implicit: group, rowContainer: rowContainer}'\r\n ></ng-container>\r\n </div>\r\n </ng-container>\r\n\r\n <ng-container [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{$implicit: group}'\r\n ></ng-container>\r\n </ng-container>\r\n\r\n <ng-template #itemTemplate let-item let-rowContainer=\"rowContainer\">\r\n <timeline-item [item]='item'\r\n [rowContainer]='rowContainer'\r\n [scale]=\"scale\"\r\n [height]=\"itemHeight\"\r\n [rowHeight]=\"rowHeight\"\r\n [locale]=\"locale\"\r\n (itemResized)=\"_onItemResized($event.event, $event.item)\"\r\n (itemMoved)=\"_onItemMoved($event.event, $event.item)\"\r\n [contentTemplate]='itemContentTemplate'\r\n ></timeline-item>\r\n </ng-template>\r\n\r\n <ng-template #itemsIterationTemplate let-group>\r\n <div *ngFor='let streamLevel of (group._streamLevels || []); trackBy: _trackById;'>\r\n <div [style.height.px]='rowHeight' class='item-row' #rowContainer>\r\n <ng-container *ngFor=\"let item of streamLevel\">\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: item, rowContainer: rowContainer}\"\r\n ></ng-container>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n <div [style.height.px]='rowHeight' class='item-row' *ngIf=\"group?._streamLevels?.length === 0\">\r\n </div>\r\n\r\n <ng-container *ngIf='group.childrenItemsExpanded'>\r\n <div *ngFor='let item of (group.childrenItems || []); trackBy: _trackById;'>\r\n <div [style.height.px]='rowHeight' *ngIf=\"!item.streamItems\" class='item-row' #rowContainer>\r\n <ng-container [ngTemplateOutlet]=\"itemTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: item, rowContainer: rowContainer}\"\r\n ></ng-container>\r\n </div>\r\n\r\n <ng-container [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{$implicit: item}'\r\n ></ng-container>\r\n </div>\r\n </ng-container>\r\n </ng-template>\r\n </div>\r\n</div>\r\n", styles: [":host{height:100%;overflow:auto;display:flex;flex-grow:1;flex-direction:row;font-size:14px;position:relative}.content-wrapper{position:relative;height:fit-content;min-height:100%}.column-separators .line{position:absolute;width:1px;height:100%;background-color:#d0d0d0}.timeline-items{display:flex;flex-direction:column;height:auto}.timeline-items .item-row{display:flex;align-items:center;flex-direction:row;position:relative;z-index:7;box-sizing:border-box}\n"] }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.StrategyManager }, { type: i0.ElementRef, decorators: [{ type: Inject, args: [ElementRef] }] }, { type: undefined, decorators: [{ type: Inject, args: [PLATFORM_ID] }] }], propDecorators: { itemTimeChanged: [{ type: Output }], itemRowChanged: [{ type: Output }], zoomChanged: [{ type: Output }], timeGridClicked: [{ type: Output }], locale: [{ type: Input }], rowHeight: [{ type: Input }], itemHeight: [{ type: Input }], headerHeight: [{ type: Input }], panelLabel: [{ type: Input }], panelWidth: [{ type: Input }], minPanelWidth: [{ type: Input }], maxPanelWidth: [{ type: Input }], offsetForChildPanelItem: [{ type: Input }], isPanelResizable: [{ type: Input }], showDateMarket: [{ type: Input }], panelItemTemplate: [{ type: Input }], itemContentTemplate: [{ type: Input }], columnSeparatorTemplate: [{ type: Input }], dateMarkerTemplate: [{ type: Input }], zooms: [{ type: Input }], items: [{ type: Input }], _onScroll: [{ type: HostListener, args: ['scroll', ['$event']] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZWxpbmUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvYW5ndWxhci1jYWxlbmRhci10aW1lbGluZS9zcmMvbGliL3RpbWVsaW5lLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL3Byb2plY3RzL2FuZ3VsYXItY2FsZW5kYXItdGltZWxpbmUvc3JjL2xpYi90aW1lbGluZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBRXZCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUVMLE1BQU0sRUFDTixXQUFXLEdBRVosTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3BELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQVUzQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM1RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDaEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQzdELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUdyRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7Ozs7Ozs7O0FBUTNELE1BQU0sT0FBTyxpQkFBaUI7SUEySDVCOzs7T0FHRztJQUNILElBQWEsS0FBSyxDQUFDLEtBQWdDO1FBQ2pELElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3BDLENBQUM7SUFFRDs7T0FFRztJQUNILElBQ0ksS0FB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QixNQUFNO2dCQUtHLGNBQWM7c0JBQXZCLE1BQU07Z0JBS0csV0FBVztzQkFBcEIsTUFBTTtnQkFLRyxlQUFlO3NCQUF4QixNQUFNO2dCQUtFLE1BQU07c0JBQWQsS0FBSztnQkFLRyxTQUFTO3NCQUFqQixLQUFLO2dCQUtHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBS0csWUFBWTtzQkFBcEIsS0FBSztnQkFLRyxVQUFVO3NCQUFsQixLQUFLO2dCQUtHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBS0csYUFBYTtzQkFBckIsS0FBSztnQkFLRyxhQUFhO3NCQUFyQixLQUFLO2dCQUtHLHVCQUF1QjtzQkFBL0IsS0FBSztnQkFLRyxnQkFBZ0I7c0JBQXhCLEtBQUs7Z0JBS0csY0FBYztzQkFBdEIsS0FBSztnQkFLRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBS0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQUtHLHVCQUF1QjtzQkFBL0IsS0FBSztnQkFLRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBTU8sS0FBSztzQkFBakIsS0FBSztnQkFRRixLQUFLO3NCQURSLEtBQUs7Z0JBbVFFLFNBQVM7c0JBRGhCLFlBQVk7dUJBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBBZnRlclZpZXdJbml0LFxyXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxyXG4gIENoYW5nZURldGVjdG9yUmVmLFxyXG4gIENvbXBvbmVudCxcclxuICBFbGVtZW50UmVmLFxyXG4gIEV2ZW50RW1pdHRlcixcclxuICBIb3N0TGlzdGVuZXIsXHJcbiAgSW5qZWN0LFxyXG4gIElucHV0LFxyXG4gIE9uRGVzdHJveSxcclxuICBPdXRwdXQsXHJcbiAgUExBVEZPUk1fSUQsXHJcbiAgVGVtcGxhdGVSZWYsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFJlc2l6ZUV2ZW50IH0gZnJvbSAnYW5ndWxhci1yZXNpemFibGUtZWxlbWVudCc7XHJcbmltcG9ydCB7IGludGVydmFsLCBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgc3RhcnRXaXRoIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQge1xyXG4gIElWaWV3TW9kZUFkYXB0b3IsXHJcbiAgSUlkT2JqZWN0LFxyXG4gIElJdGVtc0l0ZXJhdG9yLFxyXG4gIElTY2FsZSxcclxuICBJU2NhbGVHZW5lcmF0b3IsXHJcbiAgSVRpbWVsaW5lSXRlbSxcclxuICBJVGltZWxpbmVab29tLCBJWm9vbXNIYW5kbGVyLCBJU2NhbGVDb2x1bW4sIElJdGVtVGltZUNoYW5nZWRFdmVudCwgSUl0ZW1Sb3dDaGFuZ2VkRXZlbnQsIFRpbWVsaW5lVmlld01vZGVcclxufSBmcm9tICcuL21vZGVscyc7XHJcbmltcG9ydCB7IGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xyXG5pbXBvcnQgeyBNaWxsaXNlY29uZHNUb1RpbWUgfSBmcm9tIFwiLi9oZWxwZXJzL2RhdGUtaGVscGVyc1wiO1xyXG5pbXBvcnQgeyBJdGVtc0l0ZXJhdG9yIH0gZnJvbSBcIi4vaXRlbXMtaXRlcmF0b3IvaXRlbXMtaXRlcmF0b3JcIjtcclxuaW1wb3J0IHsgWm9vbXNIYW5kbGVyIH0gZnJvbSBcIi4vem9vbXMtaGFuZGxlci96b29tcy1oYW5kbGVyXCI7XHJcbmltcG9ydCB7IERlZmF1bHRab29tcyB9IGZyb20gXCIuL3pvb21zLWhhbmRsZXIvem9vbXNcIjtcclxuaW1wb3J0IHsgRHJhZ0VuZEV2ZW50IH0gZnJvbSBcImFuZ3VsYXItZHJhZ2dhYmxlLWRyb3BwYWJsZS9saWIvZHJhZ2dhYmxlLmRpcmVjdGl2ZVwiO1xyXG5pbXBvcnQgeyBTdHJhdGVneU1hbmFnZXIgfSBmcm9tIFwiLi9zdHJhdGVneS1tYW5hZ2VyXCI7XHJcbmltcG9ydCB7IFJvd0RldGVybWluYW50IH0gZnJvbSBcIi4vaGVscGVycy9yb3ctZGV0ZXJtaW5hbnRcIjtcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAndGltZWxpbmUtY2FsZW5kYXInLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi90aW1lbGluZS5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJy4vdGltZWxpbmUuY29tcG9uZW50LnNjc3MnXSxcclxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcclxufSlcclxuZXhwb3J0IGNsYXNzIFRpbWVsaW5lQ29tcG9uZW50PFZpZXdNb2RlID0gVGltZWxpbmVWaWV3TW9kZT4gaW1wbGVtZW50cyBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xyXG4gIC8qKlxyXG4gICAqIEluZGljYXRlcyB0aGUgY3VycmVudCBzaG93biBkYXRlIGluIHRoZSBtaWRkbGUgb2YgdXNlcmBzIHNjcmVlbi5cclxuICAgKi9cclxuICBwdWJsaWMgY3VycmVudERhdGU6IERhdGUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuICAvKipcclxuICAgKiAgU2NhbGUgZ2VuZXJhdG9yIGNoYW5nZXMgZGVwZW5kaW5nIG9uIGN1cnJlbnQgdmlldyB0eXBlLlxyXG4gICAqL1xyXG4gIHB1YmxpYyBzY2FsZUdlbmVyYXRvcjogSVNjYWxlR2VuZXJhdG9yO1xyXG5cclxuICAvKipcclxuICAgKiBWaWV3IG1vZGUgYWRhcHRvciBjaGFuZ2VzIGRlcGVuZGluZyBvbiBjdXJyZW50IHZpZXcgdHlwZS5cclxuICAgKi9cclxuICBwdWJsaWMgdmlld01vZGVBZGFwdG9yOiBJVmlld01vZGVBZGFwdG9yO1xyXG5cclxuICBwdWJsaWMgZGF0ZU1hcmtlckxlZnRQb3NpdGlvbjogbnVtYmVyID0gMDtcclxuXHJcbiAgcHVibGljIHNjYWxlOiBJU2NhbGUgfCB1bmRlZmluZWQ7XHJcblxyXG4gIHB1YmxpYyBpdGVtc0l0ZXJhdG9yOiBJSXRlbXNJdGVyYXRvciA9IG5ldyBJdGVtc0l0ZXJhdG9yKCk7XHJcblxyXG4gIHB1YmxpYyB6b29tc0hhbmRsZXI6IElab29tc0hhbmRsZXI8Vmlld01vZGU+ID0gbmV3IFpvb21zSGFuZGxlcjxWaWV3TW9kZT4oRGVmYXVsdFpvb21zIGFzIGFueSk7XHJcblxyXG4gIHByaXZhdGUgX2lnbm9yZU5leHRTY3JvbGxFdmVudDogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBwcml2YXRlIF9kZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEVtaXRzIGV2ZW50IHdoZW4gc3RhcnREYXRlIGFuZCBlbmREYXRlIG9mIHNvbWUgaXRlbSB3YXMgY2hhbmdlZCBieSByZXNpemluZy9tb3ZpbmcgaXQuXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIGl0ZW1UaW1lQ2hhbmdlZDogRXZlbnRFbWl0dGVyPElJdGVtVGltZUNoYW5nZWRFdmVudD4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEVtaXRzIGV2ZW50IHdoZW4gaXRlbSB3YXMgbW92ZWQgYnkgWSBheGlzLlxyXG4gICAqL1xyXG4gIEBPdXRwdXQoKSBpdGVtUm93Q2hhbmdlZDogRXZlbnRFbWl0dGVyPElJdGVtUm93Q2hhbmdlZEV2ZW50PiA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcclxuXHJcbiAgLyoqXHJcbiAgICogRW1pdHMgZXZlbnQgd2hlbiBjdXJyZW50IHpvb20gd2FzIGNoYW5nZWQuXHJcbiAgICovXHJcbiAgQE91dHB1dCgpIHpvb21DaGFuZ2VkOiBFdmVudEVtaXR0ZXI8SVRpbWVsaW5lWm9vbTxWaWV3TW9kZT4+ID0gbmV3IEV2ZW50RW1pdHRlcjxJVGltZWxpbmVab29tPFZpZXdNb2RlPj4oKTtcclxuXHJcbiAgLyoqXHJcbiAgICogRW1pdHMgZXZlbnQgd2hlbiB1c2VyIGNsaWNrZWQgc29tZXdoZXJlIG9uIHRpbWUgZ3JpZC5cclxuICAgKi9cclxuICBAT3V0cHV0KCkgdGltZUdyaWRDbGlja2VkOiBFdmVudEVtaXR0ZXI8e29yaWdpbmFsRXZlbnQ6IEV2ZW50LCByb3c6IElUaW1lbGluZUl0ZW0sIGNvbHVtbjogSVNjYWxlQ29sdW1ufT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBsb2NhbGUgdXNlZCB0byBmb3JtYXQgZGF0ZXMuIEJ5IGRlZmF1bHQgaXMgJ2VuJ1xyXG4gICAqL1xyXG4gIEBJbnB1dCgpIGxvY2FsZTogc3RyaW5nID0gJ2VuJztcclxuXHJcbiAgLyoqXHJcbiAgICogSGVpZ2h0IG9mIHRoZSBlYWNoIHJvdyBpbiBwaXhlbHMuIEJ5IGRlZmF1bHQgaXMgNDAuXHJcbiAgICovXHJcbiAgQElucHV0KCkgcm93SGVpZ2h0OiBudW1iZXIgPSA0MDtcclxuXHJcbiAgLyoqXHJcbiAgICogSGVpZ2h0IG9mIHRoZSBlYWNoIHRpbWVsaW5lIGl0ZW0gaW4gcGl4ZWxzLiBDYW4ndCBiZSBiaWdnZXIgdGhlbiAncm93SGVpZ2h0JyBwcm9wZXJ0eS4gQnkgZGVmYXVsdCBpcyAzMC5cclxuICAgKi9cclxuICBASW5wdXQoKSBpdGVtSGVpZ2h0OiBudW1iZXIgPSAzMDtcclxuXHJcbiAgLyoqXHJcbiAgICogSGVpZ2h0IG9mIHRvcCBkYXRlcyBwYW5lbCBpbiBwaXhlbHMuIEJ5IGRlZmF1bHQgaXMgNjAuXHJcbiAgICovXHJcbiAgQElucHV0KC