UNPKG

4.25 kBJavaScriptView Raw
1const getArea = (a, b) => a * b;
2const getPointDistance = (a, b) => Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2));
3export const getElementVisibleWidth = (elementWidth, xOffset, ScreenWidth) => {
4 // Element is fully visible OR scrolled right
5 if (xOffset >= 0) {
6 return xOffset + elementWidth <= ScreenWidth // is element fully visible?
7 ? elementWidth // element is fully visible;
8 : ScreenWidth - xOffset; // calculate visible width of scrolled element
9 }
10 // Element is scrolled LEFT
11 return elementWidth - xOffset; // calculate visible width of scrolled element
12};
13/*
14type Coord = {
15 x: number,
16 y: number,
17};
18
19 ~Tooltip coordinate system:~
20 The tooltip coordinates are based on the element which it is wrapping.
21 We take the x and y coordinates of the element and find the best position
22 to place the tooltip. To find the best position we look for the side with the
23 most space. In order to find the side with the most space we divide the the
24 surroundings in four quadrants and check for the one with biggest area.
25 Once we know the quandrant with the biggest area it place the tooltip in that
26 direction.
27
28 To find the areas we first get 5 coordinate points. The center and the other 4 extreme points
29 which together make a perfect cross shape.
30
31 Once we know the coordinates we can get the length of the vertices which form each quadrant.
32 Since they are squares we only need two.
33*/
34const getTooltipCoordinate = (x, y, width, height, ScreenWidth, ScreenHeight, tooltipWidth, tooltipHeight, withPointer) => {
35 // The following are point coordinates: [x, y]
36 const center = [
37 x + getElementVisibleWidth(width, x, ScreenWidth) / 2,
38 y + height / 2,
39 ];
40 const pOne = [center[0], 0];
41 const pTwo = [ScreenWidth, center[1]];
42 const pThree = [center[0], ScreenHeight];
43 const pFour = [0, center[1]];
44 // vertices
45 const vOne = getPointDistance(center, pOne);
46 const vTwo = getPointDistance(center, pTwo);
47 const vThree = getPointDistance(center, pThree);
48 const vFour = getPointDistance(center, pFour);
49 // Quadrant areas.
50 // type Areas = {
51 // area: number,
52 // id: number,
53 // };
54 const areas = [
55 getArea(vOne, vFour),
56 getArea(vOne, vTwo),
57 getArea(vTwo, vThree),
58 getArea(vThree, vFour),
59 ].map((each, index) => ({ area: each, id: index }));
60 const sortedArea = areas.sort((a, b) => b.area - a.area);
61 // deslocated points
62 const dX = 0.001;
63 const dY = height / 2;
64 // Deslocate the coordinates in the direction of the quadrant.
65 const directionCorrection = [
66 [-1, -1],
67 [1, -1],
68 [1, 1],
69 [-1, 1],
70 ];
71 const deslocateReferencePoint = [
72 [-tooltipWidth, -tooltipHeight],
73 [0, -tooltipHeight],
74 [0, 0],
75 [-tooltipWidth, 0],
76 ];
77 // current quadrant index
78 const qIndex = sortedArea[0].id;
79 const getWithPointerOffsetY = () => withPointer ? 10 * directionCorrection[qIndex][1] : 0;
80 const getWithPointerOffsetX = () => withPointer ? center[0] - 18 * directionCorrection[qIndex][0] : center[0];
81 const newX = getWithPointerOffsetX() +
82 (dX * directionCorrection[qIndex][0] + deslocateReferencePoint[qIndex][0]);
83 return {
84 x: constraintX(newX, qIndex, center[0], ScreenWidth, tooltipWidth),
85 y: center[1] +
86 (dY * directionCorrection[qIndex][1] +
87 deslocateReferencePoint[qIndex][1]) +
88 getWithPointerOffsetY(),
89 };
90};
91const constraintX = (newX, qIndex, x, ScreenWidth, tooltipWidth) => {
92 switch (qIndex) {
93 // 0 and 3 are the left side quadrants.
94 case 0:
95 case 3: {
96 const maxWidth = newX > ScreenWidth ? ScreenWidth - 10 : newX;
97 return newX < 1 ? 10 : maxWidth;
98 }
99 // 1 and 2 are the right side quadrants
100 case 1:
101 case 2: {
102 const leftOverSpace = ScreenWidth - newX;
103 return leftOverSpace >= tooltipWidth
104 ? newX
105 : newX - (tooltipWidth - leftOverSpace + 10);
106 }
107 default: {
108 return 0;
109 }
110 }
111};
112export default getTooltipCoordinate;