# All files getTooltipCoordinate.js

90% Statements 36/40
42.11% Branches 8/19
100% Functions 9/9
89.47% Lines 34/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    14024x

    1x
    24x

    1x

    10x
    10x

    1x

    6x

    6x
    6x
    6x
    6x

    6x
    6x
    6x
    6x

    6x

    24x

    24x

    6x
    6x

    6x
    6x

    6x

    6x
    6x
    6x
    6x

    6x

    6x

    1x
    6x

    6x
    6x

     const getArea = (a, b) => a * b;

    const getPointDistance = (a, b) =>
      Math.sqrt((a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2);

    export const getElementVisibleWidth = (elementWidth, xOffset, ScreenWidth) => {
      // Element is fully visible OR scrolled right
      Eif (xOffset >= 0) {
        return xOffset + elementWidth <= ScreenWidth // is element fully visible?
          ? elementWidth // element is fully visible;
          : ScreenWidth - xOffset; // calculate visible width of scrolled element
      }
      // Element is scrolled LEFT

      return elementWidth - xOffset; // calculate visible width of scrolled element
    };

    /*
    type Coord = {
      x: number,
      y: number,
    };

      ~Tooltip coordinate system:~
      The tooltip coordinates are based on the element which it is wrapping.
      We take the x and y coordinates of the element and find the best position
      to place the tooltip. To find the best position we look for the side with the
      most space. In order to find the side with the most space we divide the the
      surroundings in four quadrants and check for the one with biggest area.
      Once we know the quandrant with the biggest area it place the tooltip in that
      direction.

      To find the areas we first get 5 coordinate points. The center and the other 4 extreme points
      which together make a perfect cross shape.

      Once we know the coordincates we can get the length of the vertices which form each quadrant.
      Since they are squares we only need two.
    */

    const getTooltipCoordinate = (
      x,
      y,
      width,
      height,
      ScreenWidth,
      ScreenHeight,
      tooltipWidth,
      tooltipHeight,
      withPointer
    ) => {
      // The following are point coordinates: [x, y]
      const center = [
        x + getElementVisibleWidth(width, x, ScreenWidth) / 2,
        y + height / 2,
      ];
      const pOne = [center[0], 0];
      const pTwo = [ScreenWidth, center[1]];
      const pThree = [center[0], ScreenHeight];
      const pFour = [0, center[1]];

      // vertices
      const vOne = getPointDistance(center, pOne);
      const vTwo = getPointDistance(center, pTwo);
      const vThree = getPointDistance(center, pThree);
      const vFour = getPointDistance(center, pFour);

      // Quadrant areas.
      // type Areas = {
      //   area: number,
      //   id: number,
      // };

      const areas = [
        getArea(vOne, vFour),
        getArea(vOne, vTwo),
        getArea(vTwo, vThree),
        getArea(vThree, vFour),
      ].map((each, index) => ({ area: each, id: index }));

      const sortedArea = areas.sort((a, b) => b.area - a.area);

      // deslocated points
      const dX = 0.001;
      const dY = height / 2;

      // Deslocate the coordinates in the direction of the quadrant.
      const directionCorrection = [[-1, -1], [1, -1], [1, 1], [-1, 1]];
      const deslocateReferencePoint = [
        [-tooltipWidth, -tooltipHeight],
        [0, -tooltipHeight],
        [0, 0],
        [-tooltipWidth, 0],
      ];

      // current quadrant index
      const qIndex = sortedArea[0].id;

      const getWithPointerOffsetY = () =>
        withPointer ? 10 * directionCorrection[qIndex][1] : 0;
      const getWithPointerOffsetX = () =>
        withPointer ? center[0] - 18 * directionCorrection[qIndex][0] : center[0];

      const newX =
        getWithPointerOffsetX() +
        (dX * directionCorrection[qIndex][0] + deslocateReferencePoint[qIndex][0]);

      return {
        x: constraintX(newX, qIndex, center[0], ScreenWidth, tooltipWidth),
        y:
          center[1] +
          (dY * directionCorrection[qIndex][1] +
            deslocateReferencePoint[qIndex][1]) +
          getWithPointerOffsetY(),
      };
    };

    const constraintX = (newX, qIndex, x, ScreenWidth, tooltipWidth) => {
      switch (qIndex) {
        // 0 and 3 are the left side quadrants.
        case 0:
        case 3: {
          const maxWidth = newX > ScreenWidth ? ScreenWidth - 10 : newX;
          return newX < 1 ? 10 : maxWidth;
        }
        // 1 and 2 are the right side quadrants
        case 1:
        case 2: {
          const leftOverSpace = ScreenWidth - newX;
          return leftOverSpace >= tooltipWidth
            ? newX
            : newX - (tooltipWidth - leftOverSpace + 10);
        }
        default: {
          return 0;
        }
      }
    };

    export default getTooltipCoordinate;