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
JavaScript
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