Skip to content

Commit f33d5b3

Browse files
committed
Make sure tooltip is oriented correctly when close to edge
We now check different tooltip orientations to make sure the best one is chosen. There are 2 cases that lead to reorientation: 1. If the desired orientation (desiredPlace) is completely inside the client window, and the current orientation (place) is different from the desired one (then reorient to the desired orientation) 2. If neither the desired orientation (desiredPlace) nor the current one (place) is inside the client window, but there are other orientations that are (then reorient to an arbitrary orientation that is inside) All other cases will keep the orientation as it was before.
1 parent c44cc2d commit f33d5b3

File tree

1 file changed

+45
-128
lines changed

1 file changed

+45
-128
lines changed

src/utils/getPosition.js

Lines changed: 45 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -52,139 +52,56 @@ export default function (e, target, node, place, desiredPlace, effect, offset) {
5252
return mouseY + offset_Y + extraOffset_Y
5353
}
5454

55-
// Judge if the tooltip has over the window(screen)
56-
const outsideVertical = () => {
57-
let result = false
58-
let newPlace
59-
if (getTipOffsetTop('left') < 0 &&
60-
getTipOffsetBottom('left') <= windowHeight &&
61-
getTipOffsetBottom('bottom') <= windowHeight) {
62-
result = true
63-
newPlace = 'bottom'
64-
} else if (getTipOffsetBottom('left') > windowHeight &&
65-
getTipOffsetTop('left') >= 0 &&
66-
getTipOffsetTop('top') >= 0) {
67-
result = true
68-
newPlace = 'top'
69-
}
70-
return {result, newPlace}
71-
}
72-
const outsideLeft = () => {
73-
let {result, newPlace} = outsideVertical() // Deal with vertical as first priority
74-
if (result && outsideHorizontal().result) {
75-
return {result: false} // No need to change, if change to vertical will out of space
76-
}
77-
if (!result && getTipOffsetLeft('left') < 0 && getTipOffsetRight('right') <= windowWidth) {
78-
result = true // If vertical ok, but let out of side and right won't out of side
79-
newPlace = 'right'
80-
}
81-
return {result, newPlace}
82-
}
83-
const outsideRight = () => {
84-
let {result, newPlace} = outsideVertical()
85-
if (result && outsideHorizontal().result) {
86-
return {result: false} // No need to change, if change to vertical will out of space
87-
}
88-
if (!result && getTipOffsetRight('right') > windowWidth && getTipOffsetLeft('left') >= 0) {
89-
result = true
90-
newPlace = 'left'
91-
}
92-
return {result, newPlace}
93-
}
94-
95-
const outsideHorizontal = () => {
96-
let result = false
97-
let newPlace
98-
if (getTipOffsetLeft('top') < 0 &&
99-
getTipOffsetRight('top') <= windowWidth &&
100-
getTipOffsetRight('right') <= windowWidth) {
101-
result = true
102-
newPlace = 'right'
103-
} else if (getTipOffsetRight('top') > windowWidth &&
104-
getTipOffsetLeft('top') >= 0 &&
105-
getTipOffsetLeft('left') >= 0) {
106-
result = true
107-
newPlace = 'left'
108-
}
109-
return {result, newPlace}
110-
}
111-
const outsideTop = () => {
112-
let {result, newPlace} = outsideHorizontal()
113-
if (result && outsideVertical().result) {
114-
return {result: false}
115-
}
116-
if (!result && getTipOffsetTop('top') < 0 && getTipOffsetBottom('bottom') <= windowHeight) {
117-
result = true
118-
newPlace = 'bottom'
119-
}
120-
return {result, newPlace}
121-
}
122-
const outsideBottom = () => {
123-
let {result, newPlace} = outsideHorizontal()
124-
if (result && outsideVertical().result) {
125-
return {result: false}
126-
}
127-
if (!result && getTipOffsetBottom('bottom') > windowHeight && getTipOffsetTop('top') >= 0) {
128-
result = true
129-
newPlace = 'top'
130-
}
131-
return {result, newPlace}
132-
}
133-
134-
// Return new state to change the placement to the reverse if possible
135-
const outsideLeftResult = outsideLeft()
136-
const outsideRightResult = outsideRight()
137-
const outsideTopResult = outsideTop()
138-
const outsideBottomResult = outsideBottom()
139-
140-
if (place === 'left' && outsideLeftResult.result) {
141-
return {
142-
isNewState: true,
143-
newState: {place: outsideLeftResult.newPlace}
144-
}
145-
} else if (place === 'right' && outsideRightResult.result) {
55+
//
56+
// Functions to test whether the tooltip's sides are inside
57+
// the client window for a given orientation p
58+
//
59+
// _____________
60+
// | | <-- Right side
61+
// | p = 'left' |\
62+
// | |/ |\
63+
// |_____________| |_\ <-- Mouse
64+
// / \ |
65+
// |
66+
// |
67+
// Bottom side
68+
//
69+
let outsideLeft = p => getTipOffsetLeft(p) < 0
70+
let outsideRight = p => getTipOffsetRight(p) > windowWidth
71+
let outsideTop = p => getTipOffsetTop(p) < 0
72+
let outsideBottom = p => getTipOffsetBottom(p) > windowHeight
73+
74+
// Check whether the tooltip with orientation p is completely inside the client window
75+
let outside = p => outsideLeft(p) || outsideRight(p) || outsideTop(p) || outsideBottom(p)
76+
let inside = p => !outside(p)
77+
78+
let placesList = ['left', 'right', 'top', 'bottom']
79+
let insideList = []
80+
for (let i = 0; i < 4; i++) {
81+
let p = placesList[i]
82+
if (inside(p)) {
83+
insideList.push(p)
84+
}
85+
}
86+
87+
let isNewState = false
88+
let newPlace
89+
if (inside(desiredPlace) && desiredPlace !== place) {
90+
isNewState = true
91+
newPlace = desiredPlace
92+
} else if (insideList.length > 0 && outside(desiredPlace) && outside(place)) {
93+
isNewState = true
94+
newPlace = insideList[0]
95+
}
96+
97+
if (isNewState)
98+
{
14699
return {
147100
isNewState: true,
148-
newState: {place: outsideRightResult.newPlace}
149-
}
150-
} else if (place === 'top' && outsideTopResult.result) {
151-
return {
152-
isNewState: true,
153-
newState: {place: outsideTopResult.newPlace}
154-
}
155-
} else if (place === 'bottom' && outsideBottomResult.result) {
156-
return {
157-
isNewState: true,
158-
newState: {place: outsideBottomResult.newPlace}
159-
}
160-
}
161-
162-
// Change back to original place if possible
163-
if (place !== desiredPlace) {
164-
if (desiredPlace === 'top' && !outsideTopResult.result) {
165-
return {
166-
isNewState: true,
167-
newState: {place: 'top'}
168-
}
169-
} else if (desiredPlace === 'left' && !outsideLeftResult.result) {
170-
return {
171-
isNewState: true,
172-
newState: {place: 'left'}
173-
}
174-
} else if (desiredPlace === 'right' && !outsideRightResult.result) {
175-
return {
176-
isNewState: true,
177-
newState: {place: 'right'}
178-
}
179-
} else if (desiredPlace === 'bottom' && !outsideBottomResult.result) {
180-
return {
181-
isNewState: true,
182-
newState: {place: 'bottom'}
183-
}
101+
newState: {place: newPlace}
184102
}
185103
}
186104

187-
// Return tooltip offset position
188105
return {
189106
isNewState: false,
190107
position: {

0 commit comments

Comments
 (0)