in src/focus/focus-by-distance.ts [94:174]
public find() {
this.shortlisted = this.getElementsInDirection();
this.shortlisted = this.shortlisted.filter(el => el.rect.width && el.rect.height);
if (!this.shortlisted.length) {
return null;
}
this.shortlisted.forEach(el => el.calcPercentInShadow(this.refRect, this.dir));
const hasElementsInShadow = this.shortlisted.some(el => el.percentInShadow > 0);
// Case: No elements in shadow
// +------+
// | |
// +------+
// +---------+ --------------
// | X -> |
// +---------+---------------
// +------+ +------+
// | X | | |
// | | | |
// +------+ +------+
if (!hasElementsInShadow) {
if (isHorizontal(this.dir)) {
return null;
}
this.shortlisted.forEach(el => el.calcPrimaryDistance(this.refRect, this.dir));
const shortestPrimaryDist = this.getShortestPrimaryDist(this.shortlisted);
this.shortlisted = this.shortlisted.filter(el => el.primaryDistance === shortestPrimaryDist);
this.shortlisted.forEach(el => el.calcSecondaryDistance(this.refRect, this.dir));
// return the closest element on secondary axis
return this.shortlisted.reduce((prev, curr) =>
curr.secondaryDistance <= prev.secondaryDistance ? curr : prev,
).el;
}
this.shortlisted = this.shortlisted.filter(el => el.percentInShadow > 0);
this.shortlisted.forEach(el => el.calcPrimaryDistance(this.refRect, this.dir));
const shortestDist = this.getShortestPrimaryDist(this.shortlisted);
this.shortlisted = this.shortlisted.filter(el => el.primaryDistance === shortestDist);
// Case: Multiple elements in shadow
// +---------+ -------------------------
// | | +------+
// | | | |
// | X -> | | |
// | | +------+
// | | +------+
// +---------+--------------------------
// | |
// +------+
if (this.shortlisted.length === 1) {
return this.shortlisted[0].el;
}
// Case: Mutiple elements in shadow with equal distance
// +---------++------+
// | || |
// | || |
// | X -> |+------+
// | || |
// | || |
// +---------++------+
if (this.prevEl && this.shortlisted.some(el => el.el === this.prevEl)) {
return this.prevEl;
}
if (isHorizontal(this.dir)) {
// return top most element
return this.shortlisted.reduce((prev, curr) => (curr.rect.top < prev.rect.top ? curr : prev))
.el;
} else {
// return top left element
return this.shortlisted.reduce((prev, curr) =>
curr.rect.left < prev.rect.left ? curr : prev,
).el;
}
}