import { GanttDate , differenceInDays , GanttDateUtil } from '../utils/date' ; import { GanttDatePoint } from '../class/date-point' ; import { BehaviorSubject } from 'rxjs' ; export const primaryDatePointTop = 18 ; export const secondaryDatePointTop = 36 ; export interface GanttViewDate { date : GanttDate ; isCustom ? : boolean ; } export interface GanttViewOptions { start ? : GanttDate ; end ? : GanttDate ; min ? : GanttDate ; max ? : GanttDate ; cellWidth ? : number ; addAmount ? : number ; addUnit ? : GanttDateUtil ; } const viewOptions = { min : new GanttDate ( ) . addYears ( - 1 ) . startOfYear ( ) , max : new GanttDate ( ) . addYears ( 1 ) . endOfYear ( ) } ; export abstract class GanttView { start$ : BehaviorSubject < GanttDate > ; end$ : BehaviorSubject < GanttDate > ; get start ( ) { return this . start$ . getValue ( ) ; } get end ( ) { return this . end$ . getValue ( ) ; } primaryDatePoints : GanttDatePoint [ ] ; secondaryDatePoints : GanttDatePoint [ ] ; width : number ; cellWidth : number ; primaryWidth : number ; showTimeline = true ; showWeekBackdrop : boolean ; options : GanttViewOptions ; constructor ( start , end , options ) { this . options = Object . assign ( { } , viewOptions , options ) ; const startDate = start . isCustom ? this . startOf ( start . date ) : this . startOf ( start . date . value < this . options . start . value ? start . date : this . options . start ) ; const endDate = end . isCustom ? this . endOf ( end . date ) : this . endOf ( end . date . value > this . options . end . value ? end . date : this . options . end ) ; this . start$ = new BehaviorSubject < GanttDate > ( startDate ) ; this . end$ = new BehaviorSubject < GanttDate > ( endDate ) ; this . initialize ( ) ; } abstract startOf ( date ) ; abstract endOf ( date ) ; abstract getPrimaryWidth ( ) ; abstract getDayOccupancyWidth ( date ) ; abstract getPrimaryDatePoints ( ) ; abstract getSecondaryDatePoints ( ) ; protected getDateIntervalWidth ( start , end ) { let result = 0 ; const days = differenceInDays ( end . value , start . value ) ; for ( let i = 0 ; i < Math . abs ( days ) ; i ++ ) { result += this . getDayOccupancyWidth ( start . addDays ( i ) ) ; } result = days >= 0 ? result : - result ; return Number ( result . toFixed ( 3 ) ) ; } protected initialize ( ) { this . primaryDatePoints = this . getPrimaryDatePoints ( ) ; this . secondaryDatePoints = this . getSecondaryDatePoints ( ) ; this . width = this . getWidth ( ) ; this . cellWidth = this . getCellWidth ( ) ; this . primaryWidth = this . getPrimaryWidth ( ) ; } addStartDate ( ) { const start = this . startOf ( this . start . add ( this . options . addAmount * - 1 , this . options . addUnit ) ) ; if ( start . value >= this . options . min . value ) { const origin = this . start ; this . start$ . next ( start ) ; this . initialize ( ) ; return { start : this . start , end : origin } ; } return null ; } addEndDate ( ) { const end = this . endOf ( this . end . add ( this . options . addAmount , this . options . addUnit ) ) ; if ( end . value <= this . options . max . value ) { const origin = this . end ; this . end$ . next ( end ) ; this . initialize ( ) ; return { start : origin , end : this . end } ; } return null ; } updateDate ( start , end ) { start = this . startOf ( start ) ; end = this . endOf ( end ) ; if ( start . value < this . start . value ) { this . start$ . next ( start ) ; } if ( end . value > this . end . value ) { this . end$ . next ( end ) ; } this . initialize ( ) ; } getWidth ( ) { return this . getCellWidth ( ) * this . secondaryDatePoints . length ; } getCellWidth ( ) { return this . options . cellWidth ; } getTodayXPoint ( ) { const toady = new GanttDate ( ) . startOfDay ( ) ; if ( toady . value > this . start . value && toady . value < this . end . value ) { const x = this . getXPointByDate ( toady ) + this . getDayOccupancyWidth ( toady ) / 2 ; return x ; } else { return null ; } } getXPointByDate ( date ) { return this . getDateIntervalWidth ( this . start , date ) ; } getDateByXPoint ( x ) { const indexOfSecondaryDate = Math . floor ( x / this . getCellWidth ( ) ) ; const matchDate = this . secondaryDatePoints [ indexOfSecondaryDate ] ; const dayWidth = this . getDayOccupancyWidth ( matchDate ?. start ) ; if ( dayWidth === this . getCellWidth ( ) ) { return matchDate ?. start ; } else { const day = Math . floor ( ( x % this . getCellWidth ( ) ) / dayWidth ) + 1 ; if ( this . getCellWidth ( ) / dayWidth === 7 ) { return matchDate ?. start . addDays ( day ) ; } return matchDate ?. start . setDate ( day ) ; } } getDateRangeWidth ( start , end ) { return this . getDateIntervalWidth ( start , end . addSeconds ( 1 ) ) ; } }