Parcourir la source

remove subrender handling sizing

Adam Shaw il y a 7 ans
Parent
commit
8c52aaa0b7

+ 0 - 2
src/CalendarComponent.ts

@@ -214,8 +214,6 @@ export default class CalendarComponent extends Component<CalendarComponentProps>
   }
 
   updateSize(totalHeight, isAuto, isResize) {
-    super.updateSize(totalHeight, isAuto, isResize)
-
     this.view.updateSize(this.viewHeight, this.isHeightAuto, isResize)
     this.view.updateNowIndicator() // we need to guarantee this will run after updateSize
   }

+ 57 - 84
src/View.ts

@@ -44,6 +44,9 @@ export default abstract class View extends DateComponent<ViewProps> {
 
   queuedScroll: any
 
+  isDateSizeDirty: boolean = false
+  isEventSizeDirty: boolean = false
+
   eventOrderSpecs: any // criteria for ordering events when they have same date/time
   nextDayThreshold: Duration
 
@@ -109,46 +112,15 @@ export default abstract class View extends DateComponent<ViewProps> {
 
 
   render(props: ViewProps) {
-    this.subrender('afterSkeletonRender', [], 'beforeSkeletonUnrender', true)
-    let dateId = this.subrender('_renderDates', [ props.dateProfile ], '_unrenderDates', true)
-    this.subrender('renderBusinessHours', [ props.businessHours, props.dateProfile, dateId ], 'unrenderBusinessHours', true)
-    this.subrender('renderDateSelectionState', [ props.dateSelection, dateId ], 'unrenderDateSelection', true)
-    let evId = this.subrender('renderEvents', [ props.eventStore, props.eventUis, dateId ], 'unrenderEvents', true)
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection', true)
-    this.subrender('renderEventDragState', [ props.eventDrag, dateId ], 'unrenderEventDragState', true)
-    this.subrender('renderEventResizeState', [ props.eventResize, dateId ], 'unrenderEventResizeState', true)
-  }
-
-  _renderDates(dateProfile: DateProfile) {
-    this.renderDates(dateProfile)
-    this.afterDatesRender()
-  }
-
-  _unrenderDates() {
-    this.beforeDatesUnrender()
-    this.unrenderDates()
-  }
-
-  renderDates(dateProfile: DateProfile) {}
-  unrenderDates() {}
-  renderBusinessHours(businessHours: EventStore) {}
-  renderEvents(eventStore: EventStore, eventUis: EventUiHash) {}
-  renderEventSelection(instanceId: string) {}
-
-  renderEventDragState(state: EventInteractionUiState) {}
-  unrenderEventDragState() {}
-
-  renderEventResizeState(state: EventInteractionUiState) {}
-  unrenderEventResizeState() {}
-
-  renderDateSelectionState(selection: DateSpan) {
-    if (selection) {
-      this.renderDateSelection(selection)
-    }
+    let dateId = this.subrender('_renderDates', [ props.dateProfile ], '_unrenderDates')
+    this.subrender('renderBusinessHours', [ props.businessHours, props.dateProfile, dateId ], 'unrenderBusinessHours')
+    this.subrender('renderDateSelectionState', [ props.dateSelection, dateId ], 'unrenderDateSelection')
+    let evId = this.subrender('_renderEvents', [ props.eventStore, props.eventUis, dateId ], 'unrenderEvents')
+    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
+    this.subrender('renderEventDragState', [ props.eventDrag, dateId ], 'unrenderEventDragState')
+    this.subrender('renderEventResizeState', [ props.eventResize, dateId ], 'unrenderEventResizeState')
   }
 
-  renderDateSelection(selection: DateSpan) {
-  }
 
   // util for subclasses
   sliceEvents(eventStore: EventStore, eventUis: EventUiHash, allDay: boolean): EventRenderRange[] {
@@ -165,51 +137,25 @@ export default abstract class View extends DateComponent<ViewProps> {
   // -----------------------------------------------------------------------------------------------------------------
 
 
-  // TODO: kill
   updateSize(viewHeight: number, isAuto: boolean, isResize: boolean) {
-    let map = this.dirtySizeMethodNames
+    let { fillRenderer, eventRenderer, mirrorRenderer } = this
 
-    if (isResize || map.has('afterSkeletonRender') || map.has('_renderDates') || map.has('renderEvents')) {
+    if (isResize || this.isDateSizeDirty || this.isEventSizeDirty) {
       // sort of the catch-all sizing
       // anything that might cause dimension changes
       this.updateBaseSize(viewHeight, isAuto, isResize)
     }
 
-    if (isResize || map.has('renderBusinessHours')) {
-      this.computeBusinessHoursSize()
-    }
-
-    if (isResize || map.has('renderDateSelectionState') || map.has('renderEventDragState') || map.has('renderEventResizeState')) {
-      if (this.mirrorRenderer) {
-        this.mirrorRenderer.computeSizes()
-      }
-      if (this.fillRenderer) {
-        this.fillRenderer.computeSizes('highlight')
-      }
-    }
-
-    if (isResize || map.has('renderEvents')) {
-      this.computeEventsSize()
-    }
+    this.isDateSizeDirty = false
+    this.isEventSizeDirty = false
 
-    if (isResize || map.has('renderBusinessHours')) {
-      this.assignBusinessHoursSize()
-    }
+    fillRenderer && fillRenderer.computeSizes(isResize)
+    eventRenderer && eventRenderer.computeSizes(isResize)
+    mirrorRenderer && mirrorRenderer.computeSizes(isResize)
 
-    if (isResize || map.has('renderDateSelectionState') || map.has('renderEventDragState') || map.has('renderEventResizeState')) {
-      if (this.mirrorRenderer) {
-        this.mirrorRenderer.assignSizes()
-      }
-      if (this.fillRenderer) {
-        this.fillRenderer.assignSizes('highlight')
-      }
-    }
-
-    if (isResize || map.has('renderEvents')) {
-      this.assignEventsSize()
-    }
-
-    this.dirtySizeMethodNames = new Map()
+    fillRenderer && fillRenderer.assignSizes(isResize)
+    eventRenderer && eventRenderer.assignSizes(isResize)
+    mirrorRenderer && mirrorRenderer.assignSizes(isResize)
   }
 
 
@@ -217,30 +163,57 @@ export default abstract class View extends DateComponent<ViewProps> {
   }
 
 
-  // Skeleton Rendering
+  // Date Rendering
   // -----------------------------------------------------------------------------------------------------------------
 
 
-  afterSkeletonRender() {
+  _renderDates(dateProfile: DateProfile) {
+    this.renderDates(dateProfile)
+    this.addScroll({ isDateInit: true })
+    this.startNowIndicator() // shouldn't render yet because updateSize will be called soon
+    this.isDateSizeDirty = true
+  }
+
+  _unrenderDates() {
+    this.stopNowIndicator()
+    this.unrenderDates()
   }
 
+  renderDates(dateProfile: DateProfile) {}
+  unrenderDates() {}
+
+
+  // Event Rendering
+  // -----------------------------------------------------------------------------------------------------------------
 
-  beforeSkeletonUnrender() {
+  _renderEvents(eventStore: EventStore, eventUis: EventUiHash) {
+    this.isEventSizeDirty = true
+    this.renderEvents(eventStore, eventUis)
   }
 
+  renderEvents(eventStore: EventStore, eventUis: EventUiHash) {}
 
-  // Date Rendering
+
+  // Other Rendering (uses eventRenderer and fillRenderer)
   // -----------------------------------------------------------------------------------------------------------------
 
 
-  afterDatesRender() {
-    this.addScroll({ isDateInit: true })
-    this.startNowIndicator() // shouldn't render yet because updateSize will be called soon
-  }
+  renderBusinessHours(businessHours: EventStore) {}
+  renderEventSelection(instanceId: string) {}
 
+  renderEventDragState(state: EventInteractionUiState) {}
+  unrenderEventDragState() {}
 
-  beforeDatesUnrender() {
-    this.stopNowIndicator()
+  renderEventResizeState(state: EventInteractionUiState) {}
+  unrenderEventResizeState() {}
+
+  renderDateSelectionState(selection: DateSpan) {
+    if (selection) {
+      this.renderDateSelection(selection)
+    }
+  }
+
+  renderDateSelection(selection: DateSpan) {
   }
 
 

+ 25 - 46
src/agenda/TimeGrid.ts

@@ -71,6 +71,8 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
 
   colPositions: PositionCache
   slatPositions: PositionCache
+  isSlatSizesDirty: boolean = false
+  isColSizesDirty: boolean = false
 
   rootBgContainerEl: HTMLElement
   bottomRuleEl: HTMLElement // hidden by default
@@ -180,63 +182,37 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
     let cells = props.cells
     this.colCnt = cells.length
 
-    this.subrender('renderSlats', [ props.dateProfile ], null, true)
-    let dateId = this.subrender('renderColumns', [ props.cells, props.dateProfile ], 'unrenderColumns', true)
-    this.subrender('renderBusinessHourSegs', [ props.businessHourSegs, props.dateProfile, dateId ], 'unrenderBusinessHours', true)
-    this.subrender('renderDateSelectionSegs', [ props.dateSelectionSegs, dateId ], 'unrenderDateSelection', true)
-    let evId = this.subrender('renderEventSegs', [ props.eventSegs, dateId ], 'unrenderEvents', true)
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection', true)
-    this.subrender('renderEventDragSegs', [ props.eventDrag, dateId ], 'unrenderEventDragSegs', true)
-    this.subrender('renderEventResizeSegs', [ props.eventResize, dateId ], 'unrenderEventResizeSegs', true)
+    this.subrender('renderSlats', [ props.dateProfile ])
+    let dateId = this.subrender('renderColumns', [ props.cells, props.dateProfile ], 'unrenderColumns')
+    this.subrender('renderBusinessHourSegs', [ props.businessHourSegs, props.dateProfile, dateId ], 'unrenderBusinessHours')
+    this.subrender('renderDateSelectionSegs', [ props.dateSelectionSegs, dateId ], 'unrenderDateSelection')
+    let evId = this.subrender('renderEventSegs', [ props.eventSegs, dateId ], 'unrenderEvents')
+    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
+    this.subrender('renderEventDragSegs', [ props.eventDrag, dateId ], 'unrenderEventDragSegs')
+    this.subrender('renderEventResizeSegs', [ props.eventResize, dateId ], 'unrenderEventResizeSegs')
   }
 
-  // TODO: kill
+
   updateSize(viewHeight: number, isAuto: boolean, isResize: boolean) {
-    let map = this.dirtySizeMethodNames
+    let { fillRenderer, eventRenderer, mirrorRenderer } = this
 
-    if (isResize || map.has('renderSlats')) {
+    if (isResize || this.isSlatSizesDirty) {
       this.buildSlatPositions()
+      this.isSlatSizesDirty = false
     }
 
-    if (isResize || map.has('renderColumns')) {
+    if (isResize || this.isColSizesDirty) {
       this.buildColPositions()
+      this.isColSizesDirty = false
     }
 
-    if (isResize || map.has('renderBusinessHourSegs')) {
-      this.computeBusinessHoursSize()
-    }
+    fillRenderer.computeSizes(isResize)
+    eventRenderer.computeSizes(isResize)
+    mirrorRenderer.computeSizes(isResize)
 
-    if (isResize || map.has('renderDateSelectionSegs') || map.has('renderEventDragSegs') || map.has('renderEventResizeSegs')) {
-      if (this.mirrorRenderer) {
-        this.mirrorRenderer.computeSizes()
-      }
-      if (this.fillRenderer) {
-        this.fillRenderer.computeSizes('highlight')
-      }
-    }
-
-    if (isResize || map.has('renderEventSegs')) {
-      this.computeEventsSize()
-    }
-
-    if (isResize || map.has('renderBusinessHourSegs')) {
-      this.assignBusinessHoursSize()
-    }
-
-    if (isResize || map.has('renderDateSelectionSegs') || map.has('renderEventDragSegs') || map.has('renderEventResizeSegs')) {
-      if (this.mirrorRenderer) {
-        this.mirrorRenderer.assignSizes()
-      }
-      if (this.fillRenderer) {
-        this.fillRenderer.assignSizes('highlight')
-      }
-    }
-
-    if (isResize || map.has('renderEventSegs')) {
-      this.assignEventsSize()
-    }
-
-    this.dirtySizeMethodNames = new Map()
+    fillRenderer.assignSizes(isResize)
+    eventRenderer.assignSizes(isResize)
+    mirrorRenderer.assignSizes(isResize)
   }
 
 
@@ -256,6 +232,8 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
       false,
       true // vertical
     )
+
+    this.isSlatSizesDirty = true
   }
 
 
@@ -329,6 +307,7 @@ export default class TimeGrid extends DateComponent<TimeGridProps> {
     )
 
     this.renderContentSkeleton()
+    this.isColSizesDirty = true
   }
 
 

+ 8 - 10
src/agenda/TimeGridEventRenderer.ts

@@ -47,31 +47,29 @@ export default class TimeGridEventRenderer extends FgEventRenderer {
   }
 
 
-  computeSizes() {
+  computeSegSizes(allSegs: Seg[]) {
     let { timeGrid, segsByCol } = this
     let colCnt = timeGrid.colCnt
 
+    timeGrid.computeSegVerticals(allSegs) // horizontals relies on this
+
     if (segsByCol) {
       for (let col = 0; col < colCnt; col++) {
-        let segs = segsByCol[col]
-
-        timeGrid.computeSegVerticals(segs) // horizontals relies on this
-        this.computeSegHorizontals(segs) // compute horizontal coordinates, z-index's, and reorder the array
+        this.computeSegHorizontals(segsByCol[col]) // compute horizontal coordinates, z-index's, and reorder the array
       }
     }
   }
 
 
-  assignSizes() {
+  assignSegSizes(allSegs: Seg[]) {
     let { timeGrid, segsByCol } = this
     let colCnt = timeGrid.colCnt
 
+    timeGrid.assignSegVerticals(allSegs) // horizontals relies on this
+
     if (segsByCol) {
       for (let col = 0; col < colCnt; col++) {
-        let segs = segsByCol[col]
-
-        timeGrid.assignSegVerticals(segs)
-        this.assignSegCss(segs)
+        this.assignSegCss(segsByCol[col])
       }
     }
   }

+ 4 - 4
src/agenda/TimeGridFillRenderer.ts

@@ -33,12 +33,12 @@ export default class TimeGridFillRenderer extends FillRenderer {
     })
   }
 
-  computeSizes(type) {
-    this.timeGrid.computeSegVerticals(this.getSegsByType(type))
+  computeSegSizes(segs: Seg[]) {
+    this.timeGrid.computeSegVerticals(segs)
   }
 
-  assignSizes(type) {
-    this.timeGrid.assignSegVerticals(this.getSegsByType(type))
+  assignSegSizes(segs: Seg[]) {
+    this.timeGrid.assignSegVerticals(segs)
   }
 
 }

+ 19 - 44
src/basic/DayGrid.ts

@@ -77,6 +77,7 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
   rowEls: HTMLElement[] // set of fake row elements
   cellEls: HTMLElement[] // set of whole-day elements comprising the row's background
 
+  isCellSizesDirty: boolean = false
   rowPositions: PositionCache
   colPositions: PositionCache
 
@@ -100,13 +101,13 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
     this.rowCnt = cells.length
     this.colCnt = cells[0].length
 
-    let dateId = this.subrender('renderCells', [ props.cells, props.isRigid ], 'unrenderCells', true)
-    this.subrender('renderBusinessHourSegs', [ props.businessHourSegs, props.dateProfile, dateId ], 'unrenderBusinessHours', true)
-    this.subrender('renderDateSelectionSegs', [ props.dateSelectionSegs, dateId ], 'unrenderDateSelection', true)
-    let evId = this.subrender('renderEventSegs', [ props.eventSegs, dateId ], 'unrenderEvents', true)
-    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection', true)
-    this.subrender('renderEventDragSegs', [ props.eventDrag, dateId ], 'unrenderEventDragSegs', true)
-    this.subrender('renderEventResizeSegs', [ props.eventResize, dateId ], 'unrenderEventResizeSegs', true)
+    let dateId = this.subrender('renderCells', [ props.cells, props.isRigid ], 'unrenderCells')
+    this.subrender('renderBusinessHourSegs', [ props.businessHourSegs, props.dateProfile, dateId ], 'unrenderBusinessHours')
+    this.subrender('renderDateSelectionSegs', [ props.dateSelectionSegs, dateId ], 'unrenderDateSelection')
+    let evId = this.subrender('renderEventSegs', [ props.eventSegs, dateId ], 'unrenderEvents')
+    this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
+    this.subrender('renderEventDragSegs', [ props.eventDrag, dateId ], 'unrenderEventDragSegs')
+    this.subrender('renderEventResizeSegs', [ props.eventResize, dateId ], 'unrenderEventResizeSegs')
 
     if (this.segPopoverTile) {
       this.updateSegPopoverTile()
@@ -184,6 +185,8 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
         ])
       }
     }
+
+    this.isCellSizesDirty = true
   }
 
 
@@ -332,50 +335,22 @@ export default class DayGrid extends DateComponentProps<DayGridProps> {
   ------------------------------------------------------------------------------------------------------------------*/
 
 
-  // TODO: kill
   updateSize(viewHeight: number, isAuto: boolean, isResize: boolean) {
-    let map = this.dirtySizeMethodNames
+    let { fillRenderer, eventRenderer, mirrorRenderer } = this
 
-    if (isResize || map.has('renderCells')) {
+    if (isResize || this.isCellSizesDirty) {
       this.buildColPositions()
       this.buildRowPositions()
+      this.isCellSizesDirty = false
     }
 
-    if (isResize || map.has('renderBusinessHourSegs')) {
-      this.computeBusinessHoursSize()
-    }
-
-    if (isResize || map.has('renderDateSelectionSegs') || map.has('renderEventDragSegs') || map.has('renderEventResizeSegs')) {
-      if (this.mirrorRenderer) {
-        this.mirrorRenderer.computeSizes()
-      }
-      if (this.fillRenderer) {
-        this.fillRenderer.computeSizes('highlight')
-      }
-    }
-
-    if (isResize || map.has('renderEventSegs')) {
-      this.computeEventsSize()
-    }
-
-    if (isResize || map.has('renderBusinessHourSegs')) {
-      this.assignBusinessHoursSize()
-    }
-
-    if (isResize || map.has('renderDateSelectionSegs') || map.has('renderEventDragSegs') || map.has('renderEventResizeSegs')) {
-      if (this.mirrorRenderer) {
-        this.mirrorRenderer.assignSizes()
-      }
-      if (this.fillRenderer) {
-        this.fillRenderer.assignSizes('highlight')
-      }
-    }
-
-    if (isResize || map.has('renderEventSegs')) {
-      this.assignEventsSize()
-    }
+    fillRenderer.computeSizes(isResize)
+    eventRenderer.computeSizes(isResize)
+    mirrorRenderer.computeSizes(isResize)
 
-    this.dirtySizeMethodNames = new Map()
+    fillRenderer.assignSizes(isResize)
+    eventRenderer.assignSizes(isResize)
+    mirrorRenderer.assignSizes(isResize)
   }
 
 

+ 1 - 20
src/component/Component.ts

@@ -23,8 +23,6 @@ export default class Component<PropsType> {
   renderArgs: { [renderMethodName: string]: any[] } = {} // also indicates if rendered
   renderIds: { [renderMethodName: string]: number } = {}
   unrenderMethodNames: Map<string, string> = new Map()
-  sizeMethodNames: Map<string, string> = new Map() // never gets cleared
-  dirtySizeMethodNames: Map<string, string> = new Map()
 
   // context vars
   context: ComponentContext
@@ -66,7 +64,7 @@ export default class Component<PropsType> {
   protected unrender() {
   }
 
-  subrender(renderMethodName, args, unrenderMethodName?, sizeMethodName?): number {
+  subrender(renderMethodName, args, unrenderMethodName?): number {
     let { renderIds, renderArgs } = this
     let prevArgs = renderArgs[renderMethodName]
     let renderId = renderIds[renderMethodName]
@@ -85,28 +83,11 @@ export default class Component<PropsType> {
       if (unrenderMethodName) {
         this.unrenderMethodNames.set(renderMethodName, unrenderMethodName)
       }
-
-      // for updateSize
-      if (sizeMethodName) {
-        this.sizeMethodNames.set(renderMethodName, sizeMethodName)
-        this.dirtySizeMethodNames.set(renderMethodName, sizeMethodName)
-      }
     }
 
     return renderId
   }
 
-  // when isResize is true, causes all subrenders to have sizes updated
-  updateSize(viewHeight: number, isAuto: boolean, isResize: boolean) {
-    let methodNames = isResize ? this.sizeMethodNames : this.dirtySizeMethodNames
-
-    methodNames.forEach((sizeMethodName) => {
-      this[sizeMethodName](isResize)
-    })
-
-    this.dirtySizeMethodNames = new Map()
-  }
-
   // after destroy is called, this component won't ever be used again
   destroy() {
     let { renderArgs } = this

+ 0 - 32
src/component/DateComponent.ts

@@ -96,18 +96,6 @@ export default class DateComponent<PropsType> extends Component<PropsType> {
     }
   }
 
-  computeBusinessHoursSize() {
-    if (this.fillRenderer) {
-      this.fillRenderer.computeSizes('businessHours')
-    }
-  }
-
-  assignBusinessHoursSize() {
-    if (this.fillRenderer) {
-      this.fillRenderer.assignSizes('businessHours')
-    }
-  }
-
 
   // Date Selection
   // ---------------------------------------------------------------------------------------------------------------
@@ -179,26 +167,6 @@ export default class DateComponent<PropsType> extends Component<PropsType> {
     }
   }
 
-  computeEventsSize() {
-    if (this.fillRenderer) {
-      this.fillRenderer.computeSizes('bgEvent')
-    }
-
-    if (this.eventRenderer) {
-      this.eventRenderer.computeSizes()
-    }
-  }
-
-  assignEventsSize() {
-    if (this.fillRenderer) {
-      this.fillRenderer.assignSizes('bgEvent')
-    }
-
-    if (this.eventRenderer) {
-      this.eventRenderer.assignSizes()
-    }
-  }
-
 
   // Event Instance Selection (aka long-touch focus)
   // -----------------------------------------------------------------------------------------------------------------

+ 20 - 2
src/component/renderers/FgEventRenderer.ts

@@ -18,6 +18,7 @@ export default abstract class FgEventRenderer {
   displayEventEnd: boolean
 
   segs: Seg[] = []
+  isSizeDirty: boolean = false
 
 
   constructor(context: ComponentContext) {
@@ -34,6 +35,8 @@ export default abstract class FgEventRenderer {
 
     this.segs = segs
     this.attachSegs(segs, mirrorInfo)
+
+    this.isSizeDirty = true
     this.context.view.triggerRenderedSegs(this.segs, Boolean(mirrorInfo))
   }
 
@@ -237,11 +240,26 @@ export default abstract class FgEventRenderer {
   }
 
 
-  computeSizes() {
+  computeSizes(force: boolean) {
+    if (force || this.isSizeDirty) {
+      this.computeSegSizes(this.segs)
+    }
+  }
+
+
+  assignSizes(force: boolean) {
+    if (force || this.isSizeDirty) {
+      this.assignSegSizes(this.segs)
+      this.isSizeDirty = false
+    }
+  }
+
+
+  computeSegSizes(segs: Seg[]) {
   }
 
 
-  assignSizes() {
+  assignSegSizes(segs: Seg[]) {
   }
 
 

+ 25 - 2
src/component/renderers/FillRenderer.ts

@@ -11,6 +11,7 @@ export default abstract class FillRenderer { // use for highlight, background ev
   fillSegTag: string = 'div'
   containerElsByType: any // a hash of element sets used for rendering each fill. Keyed by fill name.
   segsByType: any
+  dirtySizeFlags: any = {}
 
 
   constructor(context: ComponentContext) {
@@ -39,6 +40,8 @@ export default abstract class FillRenderer { // use for highlight, background ev
     if (type === 'bgEvent') {
       this.context.view.triggerRenderedSegs(renderedSegs, false) // isMirror=false
     }
+
+    this.dirtySizeFlags[type] = true
   }
 
 
@@ -137,11 +140,31 @@ export default abstract class FillRenderer { // use for highlight, background ev
   }
 
 
-  computeSizes(type: string) {
+  computeSizes(force: boolean) {
+    for (let type in this.segsByType) {
+      if (force || this.dirtySizeFlags[type]) {
+        this.computeSegSizes(this.segsByType[type])
+      }
+    }
+  }
+
+
+  assignSizes(force: boolean) {
+    for (let type in this.segsByType) {
+      if (force || this.dirtySizeFlags[type]) {
+        this.assignSegSizes(this.segsByType[type])
+      }
+    }
+
+    this.dirtySizeFlags = {}
+  }
+
+
+  computeSegSizes(segs: Seg[]) {
   }
 
 
-  assignSizes(type: string) {
+  assignSegSizes(segs: Seg[]) {
   }
 
 }