Using JavaScript, I dynamically create a <div>
(call it 'popup'), populate it with content, insert it into the DOM, and then attempt to position it relative to (.clientX, .clientY) of the click event.
The positioning scheme is simple. If .clientX is in the left half of the view port, I want popup's left edge to be at .clientX. If .clientX is in the right half of the view port, I want popup's right edge to be at .clientX. Similarly for .clientY. If it is in the top half of the view port, I want popup's top edge at .clientY; if in the bottom half, popup's bottom edge should be at .clientY.
I have the horizontal alignment working correctly but can not get the vertical to work.
The algorithm I'm using is:
function positionPopupOnPage( evt ) {
var vpWH = [];
var vpW, vpH;
var coordX = evt.clientX;
var coordY = evt.clientY;
vpWH = getViewPortWidthHeight();
vpW = vpWH[0];
vpH = vpWH[1];
popup.style.position = 'absolute';
// if not display: block, .offsetWidth & .offsetHeight === 0
popup.style.display = 'block';
popup.style.zIndex = '10100';
if ( coordX > vpW/2 ) { coordX -= popup.offsetWidth; }
if ( coordY > vpH/2 ) { coordY -= popup.offsetHeight; }
popup.style.top = coordY + 'px';
popup.style.left = coordX + 'px';
} // end fn positionPopupOnPage
The function call was positionPopupOnPage(event).The function getViewPortWidthHeight() is the one given in answer to the stackoverflow question Find the exact height and width of the viewport in a cross-browser way (no Prototype/jQuery).
The problem is that popup's top/bottom edge does not align with .clientY. In the screenshot below, (.clientX, .clientY) was the the "C" in "Charlie Fowler" which is where the mouse clicked. But popup's bottom edge is way above that position.
.
--> EDIT 0 <-- (in response to @user2330270's remarks)
Popup is inserted as high up the DOM tree as possible, as the first child of <body>
. The function call is:
// insert popup above the first child of <body>
parentNode = document.getElementsByTagName("body")[0];
targetNode = parentNode.children[0];
insertPopup( parentNode, targetNode );
The function definition is:
function insertPopup( parentNode, targetNode ) {
parentNode.insertBefore(popup, targetNode);
popup.classList.add( 'popup')
existsPopup = true;
} // end fn insertPopup
There is a Pen, Table Play, at CodePen. It is the full code. The definition of positionPopupOnPage() is the third up from the bottom in the JS area, beginning at line 233.
The only CSS reaching popup is:
.popup {
position: absolute;
border: 2px solid #000;
border-radius: 10px;
width: 200px;
height: 250px;
overflow-y: auto;
background-color: rgba(0, 0, 0, .5);
color: #fff;
z-index: 1000;
display: none;
}
and the JS style assignments in positionPopupOnPage() as given above.
--> End Edit 0 <--
-->Edit 1<--
Correct the statement of the problem.The function does not work in Safari or Firefox as was initially erroneously reported. Update the positioning function to the one currently used in the Pen.
-->End Edit 1<--
Can someone help determine what is happening and how I can get popup's top/bottom edge to align with .clientY in Chrome?
Your effort and interest in my question are much appreciated. Thank you.
-Steve
The trick, for me, was to realize 4 things:
The correct function to solve the problem then becomes:
// positon popup on page relative to cursor
// position at time of click event
function positionPopupOnPage( evt ) {
var VPWH = []; // view port width / height
var intVPW, intVPH; // view port width / height
var intCoordX = evt.clientX;
var intCoordY = evt.clientY; // distance from click point to view port top
var intDistanceScrolledUp = document.body.scrollTop;
// distance the page has been scrolled up from view port top
var intPopupOffsetTop = intDistanceScrolledUp + intCoordY;
// add the two for total distance from click point y to top of page
var intDistanceScrolledLeft = document.body.scrollLeft;
var intPopupOffsetLeft = intDistanceScrolledLeft + intCoordX;
VPWH = getViewPortWidthHeight(); // view port Width/Height
intVPW = VPWH[0];
intVPH = VPWH[1];
popup.style.position = 'absolute';
// if not display: block, .offsetWidth & .offsetHeight === 0
popup.style.display = 'block';
popup.style.zIndex = '10100';
if ( intCoordX > intVPW/2 ) { intPopupOffsetLeft -= popup.offsetWidth; }
// if x is in the right half of the viewport, pull popup left by its width
if ( intCoordY > intVPH/2 ) { intPopupOffsetTop -= popup.offsetHeight; }
// if y is in the bottom half of view port, pull popup up by its height
popup.style.top = intPopupOffsetTop + 'px';
popup.style.left = intPopupOffsetLeft + 'px';
} // end fn positionPopupOnPage
With thanks to user ershwetabansal on CSS Tricks for leading me to point 2 above.