Преглед на файлове

coordcache stores positions, not offsets

Adam Shaw преди 7 години
родител
ревизия
a20ea17813
променени са 3 файла, в които са добавени 50 реда и са изтрити 89 реда
  1. 2 0
      src/agenda/TimeGrid.ts
  2. 2 0
      src/basic/DayGrid.ts
  3. 46 89
      src/common/CoordCache.ts

+ 2 - 0
src/agenda/TimeGrid.ts

@@ -231,6 +231,7 @@ export default class TimeGrid extends DateComponent {
     this.slatEls = findElements(this.slatContainerEl, 'tr')
 
     this.slatCoordCache = new CoordCache({
+      originEl: this.slatContainerEl,
       els: this.slatEls,
       isVertical: true
     })
@@ -308,6 +309,7 @@ export default class TimeGrid extends DateComponent {
     this.colEls = findElements(this.el, '.fc-day, .fc-disabled-day')
 
     this.colCoordCache = new CoordCache({
+      originEl: this.rootBgContainerEl,
       els: this.colEls,
       isHorizontal: true
     })

+ 2 - 0
src/basic/DayGrid.ts

@@ -136,10 +136,12 @@ export default class DayGrid extends DateComponent {
     this.cellEls = findElements(this.el, '.fc-day, .fc-disabled-day')
 
     this.rowCoordCache = new CoordCache({
+      originEl: this.el,
       els: this.rowEls,
       isVertical: true
     })
     this.colCoordCache = new CoordCache({
+      originEl: this.el,
       els: this.cellEls.slice(0, this.colCnt), // only the first row
       isHorizontal: true
     })

+ 46 - 89
src/common/CoordCache.ts

@@ -1,15 +1,15 @@
 import { computeInnerRect, getScrollParent } from '../util/dom-geom'
 
 export interface CoordCacheOptions {
+  originEl: HTMLElement
   els: HTMLElement[]
   isHorizontal?: boolean
   isVertical?: boolean
-  offsetParent?: HTMLElement
 }
 
 /*
 A cache for the left/right/top/bottom/width/height values for one or more elements.
-Works with both offset (from topleft document) and position (from offsetParent).
+Works with both offset (from topleft document) and position (from originEl).
 
 options:
 - els
@@ -19,13 +19,13 @@ options:
 export default class CoordCache {
 
   els: HTMLElement[] // assumed to be siblings
-  forcedOffsetParentEl: HTMLElement // options can override the natural offsetParent
-  origin: any // {left,top} position of offsetParent of els
+  originEl: HTMLElement // options can override the natural originEl
+  origin: any // {left,top} position of originEl of els
   boundingRect: any // constrain cordinates to this rectangle. {left,right,top,bottom} or null
   isHorizontal: boolean = false // whether to query for left/right/width
   isVertical: boolean = false // whether to query for top/bottom/height
 
-  // arrays of coordinates (offsets from topleft of document)
+  // arrays of coordinates (offsets from topleft of originEl)
   lefts: any
   rights: any
   tops: any
@@ -33,70 +33,45 @@ export default class CoordCache {
 
 
   constructor(options: CoordCacheOptions) {
+    this.originEl = options.originEl
     this.els = options.els
     this.isHorizontal = options.isHorizontal
     this.isVertical = options.isVertical
-    this.forcedOffsetParentEl = options.offsetParent
   }
 
 
   // Queries the els for coordinates and stores them.
   // Call this method before using and of the get* methods below.
   build() {
-    let offsetParentEl = this.forcedOffsetParentEl
-    if (!offsetParentEl && this.els.length > 0) {
-      offsetParentEl = this.els[0].offsetParent as HTMLElement
-    }
-
-    if (offsetParentEl) {
-      let offsetParentRect = offsetParentEl.getBoundingClientRect()
-      this.origin = { top: offsetParentRect.top, left: offsetParentRect.left }
-
-      this.boundingRect = this.queryBoundingRect()
+    let originEl = this.originEl
+    let originClientRect = originEl.getBoundingClientRect() // relative to viewport top-left
 
-      if (this.isHorizontal) {
-        this.buildElHorizontals()
-      }
-      if (this.isVertical) {
-        this.buildElVerticals()
-      }
-    } else {
-      this.lefts = []
-      this.rights = []
-      this.tops = []
-      this.bottoms = []
+    this.origin = {
+      top: originClientRect.top + window.scrollY,
+      left: originClientRect.left + window.scrollX
     }
-  }
-
-
-  // Destroys all internal data about coordinates, freeing memory
-  clear() {
-    this.origin = null
-    this.boundingRect = null
-    this.lefts = null
-    this.rights = null
-    this.tops = null
-    this.bottoms = null
-  }
 
+    if (this.isHorizontal) {
+      this.buildElHorizontals(originClientRect.left)
+    }
 
-  // When called, if coord caches aren't built, builds them
-  ensureBuilt() {
-    if (!this.origin) {
-      this.build()
+    if (this.isVertical) {
+      this.buildElVerticals(originClientRect.top)
     }
+
+    this.boundingRect = this.queryBoundingRect()
   }
 
 
   // Populates the left/right internal coordinate arrays
-  buildElHorizontals() {
+  buildElHorizontals(originClientLeft: number) {
     let lefts = []
     let rights = []
 
     this.els.forEach(function(node) {
       let rect = node.getBoundingClientRect()
-      lefts.push(rect.left)
-      rights.push(rect.right)
+      lefts.push(rect.left - originClientLeft)
+      rights.push(rect.right - originClientLeft)
     })
 
     this.lefts = lefts
@@ -105,14 +80,14 @@ export default class CoordCache {
 
 
   // Populates the top/bottom internal coordinate arrays
-  buildElVerticals() {
+  buildElVerticals(originClientTop: number) {
     let tops = []
     let bottoms = []
 
     this.els.forEach(function(node) {
       let rect = node.getBoundingClientRect()
-      tops.push(rect.top)
-      bottoms.push(rect.bottom)
+      tops.push(rect.top - originClientTop)
+      bottoms.push(rect.bottom - originClientTop)
     })
 
     this.tops = tops
@@ -123,15 +98,14 @@ export default class CoordCache {
   // Given a left offset (from document left), returns the index of the el that it horizontally intersects.
   // If no intersection is made, returns undefined.
   getHorizontalIndex(leftOffset) {
-    this.ensureBuilt()
-
+    let leftPosition = leftOffset - this.origin.left
     let lefts = this.lefts
     let rights = this.rights
     let len = lefts.length
     let i
 
     for (i = 0; i < len; i++) {
-      if (leftOffset >= lefts[i] && leftOffset < rights[i]) {
+      if (leftPosition >= lefts[i] && leftPosition < rights[i]) {
         return i
       }
     }
@@ -141,15 +115,14 @@ export default class CoordCache {
   // Given a top offset (from document top), returns the index of the el that it vertically intersects.
   // If no intersection is made, returns undefined.
   getVerticalIndex(topOffset) {
-    this.ensureBuilt()
-
+    let topPosition = topOffset - this.origin.top
     let tops = this.tops
     let bottoms = this.bottoms
     let len = tops.length
     let i
 
     for (i = 0; i < len; i++) {
-      if (topOffset >= tops[i] && topOffset < bottoms[i]) {
+      if (topPosition >= tops[i] && topPosition < bottoms[i]) {
         return i
       }
     }
@@ -158,73 +131,63 @@ export default class CoordCache {
 
   // Gets the left offset (from document left) of the element at the given index
   getLeftOffset(leftIndex) {
-    this.ensureBuilt()
-    return this.lefts[leftIndex]
+    return this.lefts[leftIndex] + this.origin.left
   }
 
 
-  // Gets the left position (from offsetParent left) of the element at the given index
+  // Gets the left position (from originEl left) of the element at the given index
   getLeftPosition(leftIndex) {
-    this.ensureBuilt()
-    return this.lefts[leftIndex] - this.origin.left
+    return this.lefts[leftIndex]
   }
 
 
   // Gets the right offset (from document left) of the element at the given index.
   // This value is NOT relative to the document's right edge, like the CSS concept of "right" would be.
   getRightOffset(leftIndex) {
-    this.ensureBuilt()
-    return this.rights[leftIndex]
+    return this.rights[leftIndex] + this.origin.left
   }
 
 
-  // Gets the right position (from offsetParent left) of the element at the given index.
-  // This value is NOT relative to the offsetParent's right edge, like the CSS concept of "right" would be.
+  // Gets the right position (from originEl left) of the element at the given index.
+  // This value is NOT relative to the originEl's right edge, like the CSS concept of "right" would be.
   getRightPosition(leftIndex) {
-    this.ensureBuilt()
-    return this.rights[leftIndex] - this.origin.left
+    return this.rights[leftIndex]
   }
 
 
   // Gets the width of the element at the given index
   getWidth(leftIndex) {
-    this.ensureBuilt()
     return this.rights[leftIndex] - this.lefts[leftIndex]
   }
 
 
   // Gets the top offset (from document top) of the element at the given index
   getTopOffset(topIndex) {
-    this.ensureBuilt()
-    return this.tops[topIndex]
+    return this.tops[topIndex] + this.origin.top
   }
 
 
-  // Gets the top position (from offsetParent top) of the element at the given position
+  // Gets the top position (from originEl top) of the element at the given position
   getTopPosition(topIndex) {
-    this.ensureBuilt()
-    return this.tops[topIndex] - this.origin.top
+    return this.tops[topIndex]
   }
 
   // Gets the bottom offset (from the document top) of the element at the given index.
-  // This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
+  // This value is NOT relative to the originEl's bottom edge, like the CSS concept of "bottom" would be.
   getBottomOffset(topIndex) {
-    this.ensureBuilt()
-    return this.bottoms[topIndex]
+    return this.bottoms[topIndex] + this.origin.top
   }
 
 
-  // Gets the bottom position (from the offsetParent top) of the element at the given index.
-  // This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
+  // Gets the bottom position (from the originEl top) of the element at the given index.
+  // This value is NOT relative to the originEl's bottom edge, like the CSS concept of "bottom" would be.
   getBottomPosition(topIndex) {
-    this.ensureBuilt()
-    return this.bottoms[topIndex] - this.origin.top
+    return this.bottoms[topIndex]
   }
 
 
   // Gets the height of the element at the given index
   getHeight(topIndex) {
-    this.ensureBuilt()
     return this.bottoms[topIndex] - this.tops[topIndex]
   }
 
@@ -236,17 +199,11 @@ export default class CoordCache {
   // Right now, only returns a rectangle if constrained by an overflow:scroll element.
   // Returns null if there are no elements
   queryBoundingRect() {
-    let scrollParentEl: HTMLElement
+    let scrollParentEl: HTMLElement = getScrollParent(this.els[0] || this.originEl)
 
-    if (this.els.length > 0) {
-      scrollParentEl = getScrollParent(this.els[0])
-
-      if (scrollParentEl) {
-        return computeInnerRect(scrollParentEl)
-      }
+    if (scrollParentEl) {
+      return computeInnerRect(scrollParentEl)
     }
-
-    return null
   }
 
   isPointInBounds(leftOffset, topOffset) {