Created
December 27, 2017 18:06
-
-
Save kotarok/513305f8f5d254800455326d852371ff to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var PositionObserver = function(callback, options) { | |
this.root = window; | |
this.rootMargin = this.buildRootMargin_('0'); | |
this.threasholds = undefined; | |
this.els_ = []; | |
this.callback_ = callback; | |
this.init_(options); | |
this.listen_(); | |
} | |
PositionObserver.prototype.init_ = function(option) { | |
if (!option) return false; | |
if (option.root) { | |
this.root = option.root; | |
} | |
if (option.rootMargin) { | |
this.rootMargin = this.buildRootMargin_(option.rootMargin); | |
} | |
if (option.threshold) { | |
this.threshold = option.threshold; | |
} | |
}; | |
PositionObserver.prototype.listen_ = function() { | |
if (this.els_) { | |
this.els_.forEach(function(el) { | |
if (this.checkPosChangeOf_(el)) { | |
this.callback_(el, this); | |
} | |
}.bind(this)); | |
} | |
window.requestAnimationFrame(this.listen_.bind(this)); | |
}; | |
PositionObserver.prototype.getRootRect_ = function() { | |
var root = this.root; | |
var rootRect = {}; | |
if (root === window || undefined) { | |
rootRect = { | |
top: 0, | |
left: 0, | |
width: window.innerWidth, | |
height: window.innerHeight | |
} | |
} else { | |
rootRect = root.getBoundingClientRect(); | |
} | |
return rootRect | |
}; | |
PositionObserver.prototype.getRootBounds_ = function(el) { | |
var rootRect = this.getRootRect_(); | |
var rootMargin = this.parseRootMargin_(this.rootMargin); | |
var newRootRect = { | |
top: rootMargin[0] - 0, | |
left: rootMargin[3] - 0, | |
width: rootRect.width - rootMargin[1], | |
height: rootRect.height - rootMargin[2] | |
}; | |
newRootRect.right = newRootRect.left + newRootRect.width; | |
newRootRect.bottom = newRootRect.top + newRootRect.height; | |
return newRootRect; | |
}; | |
PositionObserver.prototype.buildRootMargin_ = function(marginString) { | |
var margins = marginString.split(/\s+?/); | |
margins[1] = margins[1] || margins[0]; | |
margins[2] = margins[2] || margins[0]; | |
margins[3] = margins[3] || margins[1]; | |
return margins.join(' '); | |
}; | |
PositionObserver.prototype.parseRootMargin_ = function(marginString) { | |
marginString = this.buildRootMargin_(marginString); | |
return marginString.split(/\s+?/).map(function(margin, i) { | |
if (/%$/.test(margin)) { | |
var ratio = margin.replace(/%$/, '') / 100; | |
if (i % 2 === 1) { | |
return this.getRootRect_().width * ratio; | |
} else { | |
return this.getRootRect_().height * ratio; | |
} | |
} else { | |
return margin.replace(/px$/, ''); | |
} | |
}.bind(this)); | |
}; | |
PositionObserver.prototype.checkPosChangeOf_ = function(el) { | |
var currentRect = el.getBoundingClientRect(); | |
if (el.lastRect === undefined) { | |
el.lastRect = currentRect; | |
return true; | |
} | |
var isPositionMoved = ( | |
el.lastRect.top !== currentRect.top || | |
el.lastRect.left !== currentRect.left | |
); | |
if (isPositionMoved) { | |
return true; | |
}; | |
el.lastRect = currentRect; | |
}; | |
PositionObserver.prototype.getVisibilityOf = function(el) { | |
var rootBounds = this.getRootBounds_(); | |
var targetRect = el.getBoundingClientRect(); | |
var visibility = undefined; | |
if ( | |
targetRect.top < rootBounds.height && | |
targetRect.left < rootBounds.width && | |
targetRect.bottom > rootBounds.top && | |
targetRect.right > rootBounds.left | |
) { | |
visibility = true; | |
} else if ( | |
targetRect.top > rootBounds.height && | |
targetRect.left > rootBounds.width && | |
targetRect.bottom < rootBounds.top && | |
targetRect.right < rootBounds.left | |
) { | |
visibility = false; | |
} | |
return visibility; | |
}; | |
PositionObserver.prototype.getRelativePositionOf = function(el) { | |
var rootBounds = this.getRootBounds_(); | |
var targetRect = el.getBoundingClientRect(); | |
var relativePosition = { | |
outerX: (targetRect.left + targetRect.width) / (rootBounds.width + targetRect.width), | |
outerY: (targetRect.top + targetRect.height) / (rootBounds.height + targetRect.height), | |
innerX: targetRect.left / rootBounds.width, | |
innerY: targetRect.top / rootBounds.height | |
}; | |
return relativePosition; | |
}; | |
PositionObserver.prototype.observe = function(el) { | |
this.els_.push(el); | |
}; | |
PositionObserver.prototype.unobserve = function(el) { | |
this.els_.splice(this.els_.indexOf(el), 1); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment