github.com/jmigpin/editor@v1.6.0/util/uiutil/mousefilter/movefilter.go (about) 1 package mousefilter 2 3 import ( 4 "sync" 5 "time" 6 ) 7 8 type MoveFilter struct { 9 fps int 10 emitFn func(interface{}) 11 isMoveFn func(interface{}) bool 12 13 last struct { 14 sync.Mutex 15 timer *time.Timer 16 sent time.Time 17 moveEv interface{} 18 } 19 } 20 21 func NewMoveFilter(fps int, emitFn func(interface{}), isMoveFn func(interface{}) bool) *MoveFilter { 22 return &MoveFilter{fps: fps, emitFn: emitFn, isMoveFn: isMoveFn} 23 } 24 25 func (movef *MoveFilter) Filter(ev interface{}) { 26 if movef.isMoveFn(ev) { 27 movef.keepMoveEv(ev) 28 } else { 29 movef.sendMoveEv() 30 movef.emitFn(ev) 31 } 32 } 33 34 func (movef *MoveFilter) keepMoveEv(moveEv interface{}) { 35 frameDur := time.Second / time.Duration(movef.fps) 36 movef.last.Lock() 37 defer movef.last.Unlock() 38 if movef.last.timer != nil { 39 // Filter by discarding sequential old move events. Just update to send the last one received when it is time. 40 movef.last.moveEv = moveEv 41 } else { 42 // Send event immediately if the frame duration already passed 43 now := time.Now() 44 if now.Sub(movef.last.sent) >= frameDur { 45 movef.last.sent = now 46 movef.emitFn(moveEv) 47 } else { 48 movef.last.moveEv = moveEv // set ev to send later 49 d := frameDur - now.Sub(movef.last.sent) 50 movef.last.timer = time.AfterFunc(d, movef.sendMoveEv) 51 } 52 } 53 } 54 55 func (movef *MoveFilter) sendMoveEv() { 56 movef.last.Lock() 57 defer movef.last.Unlock() 58 if movef.last.moveEv != nil { 59 movef.last.sent = time.Now() 60 movef.emitFn(movef.last.moveEv) 61 movef.last.moveEv = nil 62 } 63 if movef.last.timer != nil { 64 movef.last.timer.Stop() 65 movef.last.timer = nil 66 } 67 }