2
0
Эх сурвалжийг харах

more efficient seg sorting

Adam Shaw 7 жил өмнө
parent
commit
151e3fc84e

+ 9 - 1
src/View.ts

@@ -72,7 +72,15 @@ export default abstract class View extends DateComponent {
 
 
     this.initHiddenDays()
     this.initHiddenDays()
     this.dateProfileGenerator = new this.dateProfileGeneratorClass(this)
     this.dateProfileGenerator = new this.dateProfileGeneratorClass(this)
-    this.eventOrderSpecs = parseFieldSpecs(this.opt('eventOrder'))
+
+    this.eventOrderSpecs = [
+      // TODO: make these parts of the eventOrder default
+      { field: 'start', order: 1 }, // earlier goes first
+      { field: 'duration', order: -1 }, // longer events go first
+      { field: 'isAllDay', order: 1 }, // put all-day events first
+    ].concat(
+      parseFieldSpecs(this.opt('eventOrder'))
+    )
 
 
     this.initialize()
     this.initialize()
   }
   }

+ 28 - 12
src/agenda/TimeGridEventRenderer.ts

@@ -1,9 +1,9 @@
 import { htmlEscape, cssToStr } from '../util/html'
 import { htmlEscape, cssToStr } from '../util/html'
 import { removeElement, applyStyle } from '../util/dom-manip'
 import { removeElement, applyStyle } from '../util/dom-manip'
 import { createFormatter } from '../datelib/formatting'
 import { createFormatter } from '../datelib/formatting'
-import EventRenderer from '../component/renderers/EventRenderer'
+import EventRenderer, { buildSegCompareObj } from '../component/renderers/EventRenderer'
 import { Seg } from '../component/DateComponent'
 import { Seg } from '../component/DateComponent'
-import { isMultiDayRange } from '../util/misc'
+import { isMultiDayRange, compareByFieldSpecs } from '../util/misc'
 
 
 const FULL_TIME_FORMAT = createFormatter({ hour: 'numeric', minute: '2-digit' })
 const FULL_TIME_FORMAT = createFormatter({ hour: 'numeric', minute: '2-digit' })
 
 
@@ -233,18 +233,24 @@ export default class TimeGridEventRenderer extends EventRenderer {
 
 
 
 
   sortForwardSegs(forwardSegs: Seg[]) {
   sortForwardSegs(forwardSegs: Seg[]) {
-    forwardSegs.sort(this.compareForwardSegs.bind(this))
-  }
-
+    let objs = forwardSegs.map(buildTimeGridSegCompareObj)
 
 
-  // A cmp function for determining which forward segment to rely on more when computing coordinates.
-  compareForwardSegs(seg1: Seg, seg2: Seg) {
-    // put higher-pressure first
-    return seg2.forwardPressure - seg1.forwardPressure ||
+    let specs = [
+      // put higher-pressure first
+      { field: 'forwardPressure', order: -1 },
       // put segments that are closer to initial edge first (and favor ones with no coords yet)
       // put segments that are closer to initial edge first (and favor ones with no coords yet)
-      (seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) ||
-      // do normal sorting...
-      this.compareEventSegs(seg1, seg2)
+      { field: 'backwardCoord', order: 1 }
+    ].concat(
+      this.view.eventOrderSpecs
+    )
+
+    objs.sort(function(obj0, obj1) {
+      return compareByFieldSpecs(obj0, obj1, specs)
+    })
+
+    return objs.map(function(c) {
+      return c._seg
+    })
   }
   }
 
 
 
 
@@ -403,3 +409,13 @@ function computeSlotSegCollisions(seg: Seg, otherSegs: Seg[], results= []) {
 function isSlotSegCollision(seg1: Seg, seg2: Seg) {
 function isSlotSegCollision(seg1: Seg, seg2: Seg) {
   return seg1.bottom > seg2.top && seg1.top < seg2.bottom
   return seg1.bottom > seg2.top && seg1.top < seg2.bottom
 }
 }
+
+
+function buildTimeGridSegCompareObj(seg: Seg) {
+  let obj = buildSegCompareObj(seg)
+
+  obj.forwardPressure = seg.forwardPressure
+  obj.backwardCoord = seg.backwardCoord
+
+  return obj
+}

+ 33 - 24
src/component/renderers/EventRenderer.ts

@@ -6,6 +6,7 @@ import { compareByFieldSpecs } from '../../util/misc'
 import { EventRenderRange, EventUi, hasBgRendering } from '../event-rendering'
 import { EventRenderRange, EventUi, hasBgRendering } from '../event-rendering'
 import { Seg } from '../DateComponent'
 import { Seg } from '../DateComponent'
 import EventApi from '../../api/EventApi'
 import EventApi from '../../api/EventApi'
+import { assignTo } from '../../util/object'
 
 
 
 
 export default class EventRenderer {
 export default class EventRenderer {
@@ -320,32 +321,16 @@ export default class EventRenderer {
 
 
 
 
   sortEventSegs(segs): Seg[] {
   sortEventSegs(segs): Seg[] {
-    segs = segs.slice() // copy
-    segs.sort(this.compareEventSegs.bind(this))
-    return segs
-  }
+    let objs = segs.map(buildSegCompareObj)
+    let specs = this.view.eventOrderSpecs
 
 
+    objs.sort(function(obj0, obj1) {
+      return compareByFieldSpecs(obj0, obj1, specs)
+    })
 
 
-  // A cmp function for determining which segments should take visual priority
-  compareEventSegs(seg1: Seg, seg2: Seg) {
-    let eventDef1 = seg1.eventRange.def
-    let eventDef2 = seg2.eventRange.def
-    let r1 = seg1.eventRange.instance.range
-    let r2 = seg2.eventRange.instance.range
-
-    let eventApi1 = new EventApi(this.view.calendar, eventDef1)
-    let eventApi2 = new EventApi(this.view.calendar, eventDef2)
-
-    return r1.start.valueOf() - r2.start.valueOf() || // earlier events go first
-      (r2.end.valueOf() - r2.start.valueOf()) - (r1.end.valueOf() - r1.start.valueOf()) || // tie? longer events go first
-      Number(eventDef1.isAllDay) - Number(eventDef2.isAllDay) || // tie? put all-day events first
-      compareByFieldSpecs(
-        eventApi1,
-        eventApi2,
-        this.view.eventOrderSpecs,
-        eventDef1.extendedProps,
-        eventDef2.extendedProps
-      )
+    return objs.map(function(c) {
+      return c._seg
+    })
   }
   }
 
 
 
 
@@ -358,6 +343,7 @@ export default class EventRenderer {
 
 
 }
 }
 
 
+
 function setElSeg(el: HTMLElement, seg: Seg) {
 function setElSeg(el: HTMLElement, seg: Seg) {
   (el as any).fcSeg = seg
   (el as any).fcSeg = seg
 }
 }
@@ -365,3 +351,26 @@ function setElSeg(el: HTMLElement, seg: Seg) {
 export function getElSeg(el: HTMLElement): Seg | null {
 export function getElSeg(el: HTMLElement): Seg | null {
   return (el as any).fcSeg || null
   return (el as any).fcSeg || null
 }
 }
+
+
+// returns a object with all primitive props that can be compared
+export function buildSegCompareObj(seg: Seg) {
+  let eventDef = seg.eventRange.def
+  let range = seg.eventRange.instance.range
+  let start = range.start.valueOf()
+  let end = range.end.valueOf()
+
+  return assignTo(
+    {},
+    eventDef.extendedProps,
+    eventDef,
+    {
+      id: eventDef.publicId,
+      start,
+      end,
+      duration: end - start,
+      isAllDay: Number(eventDef.isAllDay),
+      _seg: seg // for later retrieval
+    }
+  )
+}

+ 6 - 16
src/util/misc.ts

@@ -229,12 +229,12 @@ export function parseFieldSpecs(input) {
 }
 }
 
 
 
 
-export function compareByFieldSpecs(obj1, obj2, fieldSpecs, obj1fallback?, obj2fallback?) {
+export function compareByFieldSpecs(obj0, obj1, fieldSpecs) {
   let i
   let i
   let cmp
   let cmp
 
 
   for (i = 0; i < fieldSpecs.length; i++) {
   for (i = 0; i < fieldSpecs.length; i++) {
-    cmp = compareByFieldSpec(obj1, obj2, fieldSpecs[i], obj1fallback, obj2fallback)
+    cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i])
     if (cmp) {
     if (cmp) {
       return cmp
       return cmp
     }
     }
@@ -244,23 +244,13 @@ export function compareByFieldSpecs(obj1, obj2, fieldSpecs, obj1fallback?, obj2f
 }
 }
 
 
 
 
-export function compareByFieldSpec(obj1, obj2, fieldSpec, obj1fallback, obj2fallback) {
+export function compareByFieldSpec(obj0, obj1, fieldSpec) {
   if (fieldSpec.func) {
   if (fieldSpec.func) {
-    return fieldSpec.func(obj1, obj2)
+    return fieldSpec.func(obj0, obj1)
   }
   }
 
 
-  let val1 = obj1[fieldSpec.field]
-  let val2 = obj2[fieldSpec.field]
-
-  if (val1 == null && obj1fallback) {
-    val1 = obj1fallback[fieldSpec.field]
-  }
-
-  if (val2 == null && obj2fallback) {
-    val2 = obj2fallback[fieldSpec.field]
-  }
-
-  return flexibleCompare(val1, val2) * (fieldSpec.order || 1)
+  return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field])
+    * (fieldSpec.order || 1)
 }
 }