Skip to content

Commit 4fb4b40

Browse files
authored
Merge pull request #391 from hassanbot/tooltip-orientation
fix(positioning): make sure tooltip is oriented correctly when close to edge
2 parents c44cc2d + 6f01ed8 commit 4fb4b40

File tree

1 file changed

+44
-128
lines changed

1 file changed

+44
-128
lines changed

src/utils/getPosition.js

+44-128
Original file line numberDiff line numberDiff line change
@@ -52,139 +52,55 @@ 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 = ['top', 'bottom', 'left', 'right']
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) {
14698
return {
14799
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-
}
100+
newState: {place: newPlace}
184101
}
185102
}
186103

187-
// Return tooltip offset position
188104
return {
189105
isNewState: false,
190106
position: {

0 commit comments

Comments
 (0)