UNPKG

devexpress-gantt

Version:

DevExpress Gantt Control

633 lines (609 loc) 28.3 kB
import { Point } from "@devexpress/utils/lib/geometry/point"; import { DomUtils } from "@devexpress/utils/lib/utils/dom"; import { Position, TaskTitlePosition } from "../../View/Helpers/Enums"; import { GanttView } from "../../View/GanttView"; import { GridElementInfo } from "../../View/Helpers/GridElementInfo"; import { GridLayoutCalculator } from "../../View/Helpers/GridLayoutCalculator"; import { PdfDependencyLineInfo } from "./DataObjects/DependencyLineInfo"; import { PdfTaskResourcesInfo } from "./DataObjects/TaskResourcesInfo"; import { PdfTaskInfo } from "./DataObjects/TaskInfo"; import { Color } from "./Table/Color"; import { StyleDef } from "./Table/StyleDef"; import { Margin } from "./Table/Margin"; import { CellDef } from "./Table/CellDef"; import { TaskAreaExportHelper } from "./TaskAreaHelper"; import { GanttPdfExportProps } from "./Settings/Props"; import { IGanttExportInfo, IGanttPageExportInfo, IGanttTableExportInfo, IGanttObjectExportInfo, PdfPageTableNames } from "./Interfaces"; import { Size } from "@devexpress/utils/lib/geometry/size"; import { PdfGanttPaginator } from "./Paging/Paginator"; import { ScalingHelper } from "./ScalingHelper"; import { PdfTimeMarkerInfo } from "./DataObjects/TimeMarkerInfo"; import { DataExportMode, ExportMode } from "./Settings/Enums"; import { PredefinedStyles } from "./Table/PredefinedStyles"; export class GanttExportCalculator implements IGanttExportInfo { public static _defaultPageMargin: number = 10; public static _autoFormatWidthAddStock = 1; private _owner: GanttView; private _taskAreaHelper: TaskAreaExportHelper; private _scalingHelper: ScalingHelper; private _chartTableBodyMatrix: Array<Array<CellDef>>; private _chartTableScaleTopMatrix: Array<Array<CellDef>>; private _chartTableScaleBottomMatrix: Array<Array<CellDef>>; private _treeListHeaderMatrix: Array<Array<CellDef>>; private _treeListBodyMatrix: Array<Array<CellDef>>; private _chartScaleTableStyle: StyleDef; private _chartMainTableStyle: StyleDef; private _treeListTableStyle: StyleDef; private _headerTableTop: number; private _mainTableTop: number; private _chartLeft: number; private _treeListLeft: number; private _mainTableHeight: number; private _treeListWidth: number; private _chartWidth: number; private _dataObjectLeftDelta: number; private _dataObjectTopDelta: number; private _tasksInfo: Array<PdfTaskInfo>; private _dependenciesInfo: Array<PdfDependencyLineInfo>; private _resourcesInfo: Array<PdfTaskResourcesInfo>; private _timeMarkersInfo: Array<PdfTimeMarkerInfo>; private _props: GanttPdfExportProps; private _settingsForPaging: GanttPdfExportProps; constructor(owner: GanttView, props?: Record<string, any>) { this._owner = owner; this._props = new GanttPdfExportProps(props); this._props.margins ??= new Margin(GanttExportCalculator._defaultPageMargin); } public get chartTableScaleTopMatrix(): Array<Array<CellDef>> { this._chartTableScaleTopMatrix ??= this.calculateChartScaleMatrix(0); return this._chartTableScaleTopMatrix; } public get chartTableScaleBottomMatrix(): Array<Array<CellDef>> { this._chartTableScaleBottomMatrix ??= this.calculateChartScaleMatrix(1); return this._chartTableScaleBottomMatrix; } public get chartTableBodyMatrix(): Array<Array<CellDef>> { if(!this._chartTableBodyMatrix) this.calculateChartTableBodyMatrix(); return this._chartTableBodyMatrix; } public get treeListHeaderMatrix(): Array<Array<CellDef>> { if(!this._treeListHeaderMatrix) this.calculateTreeListTableHeaderMatrix(); return this._treeListHeaderMatrix; } public get treeListBodyMatrix(): Array<Array<CellDef>> { if(!this._treeListBodyMatrix) this.calculateTreeListTableBodyMatrix(); return this._treeListBodyMatrix; } public getPages(pdfDoc: any): Array<IGanttPageExportInfo> { const paginator = new PdfGanttPaginator(pdfDoc, this.settings, this.createGlobalInfo()); return paginator.getPages(); } public get settings(): GanttPdfExportProps { return this.settingsForPaging; } protected get layoutCalculator(): GridLayoutCalculator { return this._taskAreaHelper.layoutCalculator; } protected get taskAreaHelper(): TaskAreaExportHelper { this._taskAreaHelper ??= new TaskAreaExportHelper(this._owner, this._props); return this._taskAreaHelper; } protected get scalingHelper(): ScalingHelper { this._scalingHelper ??= new ScalingHelper(this._props?.pdfDoc); return this._scalingHelper; } protected get visibleTaskIndices(): Array<number> { return this.taskAreaHelper.visibleTaskIndices; } protected get baseCellWidth(): number { return this.taskAreaHelper.baseCellSize.width; } protected get baseCellHeight(): number { return this.taskAreaHelper.baseCellHeight; } protected get chartScaleTableStyle(): StyleDef { this._chartScaleTableStyle ??= this.getChartScaleTableStyle(); return this._chartScaleTableStyle; } protected get chartMainTableStyle(): StyleDef { this._chartMainTableStyle ??= this.getChartMainTableStyle(); return this._chartMainTableStyle; } protected get treeListTableStyle(): StyleDef { if(!this._treeListTableStyle) this.calculateTreeListTableStyle(); return this._treeListTableStyle; } protected get pageTopMargin(): number { return this._props.margins.top; } protected get pageLeftMargin(): number { return this._props.margins.left; } protected get pageRightMargin(): number { return this._props.margins.right; } protected get pageBottomMargin(): number { return this._props.margins.bottom; } protected get headerTableTop(): number { this._headerTableTop ??= this.pageTopMargin; return this._headerTableTop; } protected get mainTableTop(): number { this._mainTableTop ??= this.getMainTableTop(); return this._mainTableTop; } protected get exportDataMode(): DataExportMode { return this._props.exportDataMode; } protected getMainTableTop(): number { return this.headerTableTop + this.headerTableHeight - this.taskAreaHelper.offsetTop; } protected get chartLeft(): number { this._chartLeft ??= this.getChartLeft(); return this._chartLeft; } protected getChartLeft(): number { const mode = this._props?.exportMode || ExportMode.all; const visibleLeft = mode === ExportMode.chart ? this.pageLeftMargin : this.treeListLeft + this.treeListWidth; const left = visibleLeft - this.taskAreaHelper.offsetLeft; return left; } protected get treeListLeft(): number { this._treeListLeft ??= this.pageLeftMargin; return this._treeListLeft; } protected get headerTableHeight(): number { return 2 * this.taskAreaHelper.headerRowHeight; } protected get mainTableHeight(): number { this._mainTableHeight ??= this.taskAreaHelper.taskAreaHeight; return this._mainTableHeight; } protected get treeListWidth(): number { this._treeListWidth ??= this.getTreeListTableWidth(); return this._treeListWidth; } protected getTreeListTableWidth(): number { const headerWidths = this.treeListHeaderMatrix[0].map((c, i) => this.getTreeListColumnWidth(i)); return headerWidths?.reduce((acc, v) => acc += v, 0) ?? 0; } protected get chartWidth(): number { if(!this._chartWidth) { const row = this.chartTableScaleBottomMatrix[0]; this._chartWidth = row.reduce((acc, v) => acc += v.styles.cellWidth.hasValue() ? v.styles.cellWidth.getValue() as number : this.baseCellWidth , 0); } return this._chartWidth; } protected get settingsForPaging(): GanttPdfExportProps { if(!this._settingsForPaging) { this._settingsForPaging = new GanttPdfExportProps(this._props); this.prepareAutoFormat(this._settingsForPaging); this.scalingHelper.scalePageMargins(this._settingsForPaging); } return this._settingsForPaging; } prepareAutoFormat(settings: GanttPdfExportProps): void { if(settings.format === GanttPdfExportProps.autoFormatKey) { settings.format = null; const landscape = settings.landscape; const width = this.autoFormatWidth; const height = this.autoFormatHeight; const rotateLanscape = (landscape && height > width) || (!landscape && height < width); if(rotateLanscape) settings.landscape = !landscape; settings.pageSize = new Size(width, height); } } protected get autoFormatWidth(): number { const mode = this._props?.exportMode || ExportMode.all; const hasChart = mode !== ExportMode.treeList; let width = this.pageRightMargin; if(hasChart) width += this.chartLeft + this.chartWidth; else width += this.treeListLeft + this.treeListWidth; return width + GanttExportCalculator._autoFormatWidthAddStock; } protected get autoFormatHeight(): number { return this.mainTableTop + this.mainTableHeight + this.pageBottomMargin; } protected createGlobalInfo(): IGanttPageExportInfo { const info: IGanttPageExportInfo = { objects: this._canExportChart() ? this.getGanttObjectsInfo() : null, tables: this.getTablesInfo() }; this.scalingHelper.scaleSizes(info); return info; } protected getTablesInfo(): Record<string, IGanttTableExportInfo> { const info = { }; if(this._canExportTreelist()) { info[PdfPageTableNames.treeListHeader] = this.createTreeListHeaderTableInfo(); info[PdfPageTableNames.treeListMain] = this.createTreeListMainTableInfo(); } if(this._canExportChart()) { info[PdfPageTableNames.chartMain] = this.createChartMainTableInfo(); info[PdfPageTableNames.chartScaleTop] = this._createChartScaleTopInfo(); info[PdfPageTableNames.chartScaleBottom] = this._createChartScaleBottomInfo(); } return info; } private get exportMode(): ExportMode { return this._props?.exportMode ?? ExportMode.all; } private _canExportTreelist(): boolean { return this.exportMode === ExportMode.all || this.exportMode === ExportMode.treeList; } private _canExportChart(): boolean { return this.exportMode === ExportMode.all || this.exportMode === ExportMode.chart; } private get _predefinedFont(): string { const font = this._props?.pdfDoc?.getFont(); return font?.fontName || this._props?.font?.name; } private _createChartScaleTopInfo(): IGanttTableExportInfo { return { name: PdfPageTableNames.chartScaleTop, size: new Size(this.chartWidth, this.taskAreaHelper.headerRowHeight), position: new Point(this.chartLeft, this.headerTableTop), style: this.chartScaleTableStyle, baseCellSize: new Size(this.baseCellWidth, this.taskAreaHelper.headerRowHeight), cells: this.chartTableScaleTopMatrix }; } private _createChartScaleBottomInfo(): IGanttTableExportInfo { const rowHeight = this.taskAreaHelper.headerRowHeight; return { name: PdfPageTableNames.chartScaleBottom, size: new Size(this.chartWidth, rowHeight), position: new Point(this.chartLeft, this.headerTableTop + rowHeight), style: this.chartScaleTableStyle, baseCellSize: new Size(this.baseCellWidth, rowHeight), cells: this.chartTableScaleBottomMatrix }; } protected createChartMainTableInfo(): IGanttTableExportInfo { const info: IGanttTableExportInfo = { name: PdfPageTableNames.chartMain, size: new Size(this.chartWidth, this.mainTableHeight), position: new Point(this.chartLeft, this.mainTableTop), style: this.chartMainTableStyle, baseCellSize: new Size(this.baseCellWidth, this.baseCellHeight), cells: this.chartTableBodyMatrix, hideRowLines: !this._owner.settings.areHorizontalBordersEnabled }; return info; } protected createTreeListHeaderTableInfo(): IGanttTableExportInfo { const info: IGanttTableExportInfo = { name: PdfPageTableNames.treeListHeader, size: new Size(this.treeListWidth, this.headerTableHeight), position: new Point(this.treeListLeft, this.headerTableTop), style: this.treeListTableStyle, baseCellSize: new Size(null, this.headerTableHeight), cells: this.treeListHeaderMatrix }; return info; } protected createTreeListMainTableInfo(): IGanttTableExportInfo { const info: IGanttTableExportInfo = { name: PdfPageTableNames.treeListMain, size: new Size(this.treeListWidth, this.mainTableHeight), position: new Point(this.treeListLeft, this.mainTableTop), style: this.treeListTableStyle, baseCellSize: new Size(null, this.baseCellHeight), cells: this.treeListBodyMatrix, hideRowLines: !this._owner.settings.areHorizontalBordersEnabled }; return info; } protected calculateChartScaleMatrix(index: number): Array<Array<CellDef>> { const helper = this.taskAreaHelper; const ranges = helper.scaleRanges; const row = new Array<CellDef>(); const start = ranges[index][0]; const end = ranges[index][1]; for(let j = start; j <= end; j++) { const cell = new CellDef(this._owner.renderHelper.getScaleItemText(j, helper.scales[index])); cell.styles.cellPadding.assign(0); cell.styles.minCellHeight = this.taskAreaHelper.headerRowHeight; const cellWidth = index === 0 ? helper.scaleTopWidths[j] : helper.scaleBottomWidths[j]; cell.styles.cellWidth.assign(cellWidth); row.push(cell); } return [row]; } protected calculateChartTableBodyMatrix(): void { this._chartTableBodyMatrix = new Array<Array<CellDef>>(); if(this.visibleTaskIndices.length > 0) this.visibleTaskIndices.forEach(i => this._chartTableBodyMatrix.push(this.createChartTableBodyRow(i))); else this._chartTableBodyMatrix.push(this.createChartTableBodyRow(-1)); } protected createChartTableBodyRow(index: number): Array<CellDef> { const etalon = new CellDef(); if(this.rowHasChildren(index)) etalon.styles.fillColor.assign(this.taskAreaHelper.parentRowBackColor); return this.chartTableScaleBottomMatrix[0].map((c) => { const cell = new CellDef(etalon); cell.styles.cellWidth.assign(c.styles.cellWidth); return cell; }); } protected rowHasSelection(index: number): boolean { return this._owner.rowHasSelection(index); } protected rowHasChildren(index: number): boolean { return this._owner.rowHasChildren(index); } protected calculateTreeListTableHeaderMatrix(): void { this._treeListHeaderMatrix = new Array<Array<CellDef>>(); const owner = this._owner; const colCount = owner.getTreeListColCount(); const row = new Array<CellDef>(); for(let j = 0; j < colCount; j++) { const cell = new CellDef(owner.getTreeListHeaderInfo(j)); cell.styles.minCellHeight = 2 * this.taskAreaHelper.headerRowHeight; row.push(cell); } this._treeListHeaderMatrix.push(row); } protected calculateTreeListTableBodyMatrix(): void { this._treeListBodyMatrix = new Array<Array<CellDef>>(); const hasTasks = this.visibleTaskIndices.length > 0; if(hasTasks) this.fillTreeListTableBodyMatrix(this._treeListBodyMatrix); else this.fillTreeListEmptyTableBodyMatrix(this._treeListBodyMatrix); } protected fillTreeListTableBodyMatrix(matrix: Array<Array<CellDef>>): void { const visibleTaskIndices = this.visibleTaskIndices; const colCount = this.treeListHeaderMatrix[0].length; for(let i = 0; i < visibleTaskIndices.length; i++) { const row = new Array<CellDef>(); const visibleIndex = visibleTaskIndices[i]; const taskKey = this._owner.getTask(visibleIndex)?.id; for(let j = 0; j < colCount; j++) { const cell = new CellDef(this._owner.getTreeListCellInfo(visibleIndex, j, taskKey)); if(!cell.styles.cellWidth.hasValue()) cell.styles.cellWidth.assign(this.getTreeListColumnWidth(j)); if(this.rowHasChildren(visibleTaskIndices[i])) cell.styles.fillColor.assign(this.taskAreaHelper.parentRowBackColor); row.push(cell); } matrix.push(row); } } protected fillTreeListEmptyTableBodyMatrix(matrix: Array<Array<CellDef>>): void { const row = new Array<CellDef>(); const cell = new CellDef(this._owner.getTreeListEmptyDataCellInfo()); cell.styles.cellWidth.assign(this.treeListWidth); cell.styles.halign = PredefinedStyles.horizontalAlign[1]; cell.styles.valign = PredefinedStyles.verticalAlign[1]; row.push(cell); matrix.push(row); } protected getTreeListColumnWidth(colIndex: number): number { const info = this.treeListHeaderMatrix[0][colIndex]; const style = info && info.styles; const numWidth = style.cellWidth.getValue() as number; return numWidth || style.minCellWidth || 0; } protected getObjectsLeftOffset(isTask: boolean = false): number { let offset = this.dataObjectLeftDelta; if(!isTask) offset += this.taskAreaHelper.customRangeLeftOffset; return offset; } protected get dataObjectLeftDelta(): number { this._dataObjectLeftDelta ??= this.getDataObjectLeftDelta(); return this._dataObjectLeftDelta; } protected get dataObjectTopDelta(): number { this._dataObjectTopDelta ??= this.getDataObjectTopDelta(); return this._dataObjectTopDelta; } protected getChartScaleTableStyle(): StyleDef { const style = new StyleDef(this.taskAreaHelper.scaleTableStyle); if(this._predefinedFont) style.font = this._predefinedFont; return style; } protected getChartMainTableStyle(): StyleDef { const style = new StyleDef(this.taskAreaHelper.chartMainTableStyle); if(this._predefinedFont) style.font = this._predefinedFont; return style; } protected calculateTreeListTableStyle(): void { this._treeListTableStyle = new StyleDef(this._owner.getTreeListTableStyle()); this._treeListTableStyle.fillColor.assign(this.chartMainTableStyle.fillColor); this._treeListTableStyle.lineColor.assign(this.chartMainTableStyle.lineColor); if(this._predefinedFont) this._treeListTableStyle.font = this._predefinedFont; } public getGanttObjectsInfo(): IGanttObjectExportInfo { return { tasks: this.tasksInfo, dependencies: this.dependenciesInfo, resources: this.resourcesInfo, timeMarkers: this.timeMarkersInfo }; } public get tasksInfo(): Array<PdfTaskInfo> { this._tasksInfo ??= this.calculateTasksInfo(); return this._tasksInfo; } public get dependenciesInfo(): Array<PdfDependencyLineInfo> { this._dependenciesInfo ??= this.calculateDependenciesInfo(); return this._dependenciesInfo; } public get resourcesInfo(): Array<PdfTaskResourcesInfo> { this._resourcesInfo ??= this.calculateResourcesInfo(); return this._resourcesInfo; } public get timeMarkersInfo(): Array<PdfTimeMarkerInfo> { this._timeMarkersInfo ??= this.calculateTimeMarkersInfoInfo(); return this._timeMarkersInfo; } protected getDataObjectLeftDelta(): number { return this.chartLeft - this.taskAreaHelper.objectsLeftDelta; } protected getDataObjectTopDelta(): number { return this.headerTableTop + this.headerTableHeight - this.taskAreaHelper.objectsTopDelta; } calculateTasksInfo(): Array<PdfTaskInfo> { const result = new Array<PdfTaskInfo>(); this.visibleTaskIndices.forEach(i => result.push(this.calculateTaskInfo(i))); return result; } calculateTaskInfo(index: number): PdfTaskInfo { const info = new PdfTaskInfo(); const taskElementInfo = this.layoutCalculator.getTaskElementInfo(index); info.taskColor = this.getTaskColor(index); info.sidePoints = this.getTaskSidePoints(index); info.isMilestone = taskElementInfo.className.indexOf(GridLayoutCalculator.milestoneClassName) > 0; if(!info.isMilestone) { info.isSmallTask = taskElementInfo.className.indexOf(GridLayoutCalculator.smallTaskClassName) > 0; info.isParent = taskElementInfo.className.indexOf(GridLayoutCalculator.parentTaskClassName) > 0; this.appendTaskTitle(info, index); this.appendTaskProgress(info, index); } return info; } protected appendTaskTitle(info: PdfTaskInfo, index: number): void { const textPosition = this._owner.settings.taskTitlePosition; const isTextHidden = info.isSmallTask && textPosition !== TaskTitlePosition.Outside || textPosition === TaskTitlePosition.None; if(!isTextHidden) { info.text = this._owner.getTaskText(index); info.textPosition = textPosition; info.textStyle = this.getTaskTextStyle(index); } } protected appendTaskProgress(info: PdfTaskInfo, index: number): void { const progressInfo = this.layoutCalculator.getTaskProgressElementInfo(index); info.progressWidth = progressInfo.size.width; info.progressColor = this.getTaskProgressColor(index); info.progressColor.applyOpacityToBackground(info.taskColor); } protected getTaskSidePoints(index: number): Array<Point> { const points = this.layoutCalculator.getTaskSidePoints(index); points.forEach(p => { p.x += this.getObjectsLeftOffset(true); p.y += this.dataObjectTopDelta; }); return points; } protected getTaskColor(index: number): Color { const color = this.taskAreaHelper.getTaskElementBackColor(index, GridLayoutCalculator.taskClassName); return new Color(color); } protected getTaskProgressColor(index: number): Color { return new Color(this.taskAreaHelper.getTaskElementBackColor(index, GridLayoutCalculator.taskProgressClassName)); } getTaskTextStyle(index: number): StyleDef { const style = new StyleDef(); style.cellPadding.assign(0); style.assign(this.taskAreaHelper.getTaskElementStyle(index, GridLayoutCalculator.taskTitleClassName)); return style; } calculateDependenciesInfo(): Array<PdfDependencyLineInfo> { const result = new Array<PdfDependencyLineInfo>(); const helper = this.taskAreaHelper; const fillColor = new Color(helper.dependencyColor); helper.connectorLines.forEach(line => result.push(this.createLineInfo(line, fillColor, helper.arrowWidth))); return result; } protected createLineInfo(line: GridElementInfo, fillColor: Color, arrowWidth: number): PdfDependencyLineInfo { const info = new PdfDependencyLineInfo(); info.fillColor = fillColor; const isArrow = line.className.indexOf(GridLayoutCalculator.arrowClassName) > -1; if(isArrow) { const position = this.layoutCalculator.getArrowPositionByClassName(line.className); info.arrowInfo = { position: position, width: arrowWidth }; info.points = [ this.getArrowTopCorner(line, position, arrowWidth) ]; } else info.points = this.getLinePoints(line); return info; } protected getArrowTopCorner(info: GridElementInfo, position: Position, width: number): Point { let x = info.position.x + this.getObjectsLeftOffset(); let y = info.position.y + this.dataObjectTopDelta; switch(position) { case Position.Left: x += width; break; case Position.Top: y += width; } return new Point(x, y); } protected getLinePoints(line: GridElementInfo): Array<Point> { const x1 = line.position.x + this.getObjectsLeftOffset(); const y1 = line.position.y + this.dataObjectTopDelta; const x2 = x1 + line.size.width; const y2 = y1 + line.size.height; return [ new Point(x1, y1), new Point(x2, y2) ]; } calculateResourcesInfo(): Array<PdfTaskResourcesInfo> { let result = new Array<PdfTaskResourcesInfo>(); this.taskAreaHelper.resourcesElements.forEach(rw => result = result.concat(this.calculateResourcesInLine(rw))); return result; } protected calculateResourcesInLine(wrapper: HTMLElement): Array<PdfTaskResourcesInfo> { const result = new Array<PdfTaskResourcesInfo>(); if(wrapper) { let left = DomUtils.pxToInt(wrapper.style.left) + this.getObjectsLeftOffset(); const top = DomUtils.pxToInt(wrapper.style.top) + this.dataObjectTopDelta; const resources = wrapper.getElementsByClassName(GridLayoutCalculator.taskResourceClassName); for(let i = 0; i < resources.length; i++) { const resource = resources[i]; if(this.taskAreaHelper.isElementVisible(resource)) { const style = getComputedStyle(resource); left += this.getMargin(style).left; result.push(new PdfTaskResourcesInfo(resource.textContent, new StyleDef(style), left, top)); left += DomUtils.pxToInt(style.width); } } } return result; } calculateTimeMarkersInfoInfo(): Array<PdfTimeMarkerInfo> { const result = new Array<PdfTimeMarkerInfo>(); const stripLines = this.taskAreaHelper.stripLinesElements; stripLines.forEach(s => result.push(this.createTimeMarkerInfo(s, true))); const noWorkIntervals = this.taskAreaHelper.noWorkingIntervalsElements; noWorkIntervals.forEach(s => result.push(this.createTimeMarkerInfo(s, false))); return result; } protected createTimeMarkerInfo(element: HTMLElement, isStripLine: boolean): PdfTimeMarkerInfo { const style = getComputedStyle(element); const left = DomUtils.pxToInt(style.left) + this.getObjectsLeftOffset(); const top = DomUtils.pxToInt(style.top) + this.dataObjectTopDelta; const width = DomUtils.pxToInt(style.width); const height = DomUtils.pxToInt(style.height); return new PdfTimeMarkerInfo(new Point(left, top), new Size(width, height), new Color(style.backgroundColor), new Color(style.borderLeftColor), isStripLine); } protected getMargin(style: CSSStyleDeclaration): Margin { const margin = new Margin(0); if(style) { let marginCss = style.margin; if(!marginCss) { marginCss += style.marginTop || "0"; marginCss += " " + style.marginRight || "0"; marginCss += " " + style.marginBottom || "0"; marginCss += " " + style.marginLeft || "0"; } margin.assign(marginCss); } return margin; } }