public find()

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;
    }
  }