I am creating a tooltip and am having some problems with positioning it.
The tooltip is set to position: absolute, and I have a handler for mouse events that modifies it's top and left CSS depending on the pageX and pageY.
Now, I know I can just set the top to pageY and left to pageX. That will make the tooltip pop up to the bottom-right. I'm trying to orient it where it pops up on the top-right when there is room, but if it would be out of the viewport on the Y-axis, drop to the bottom-right position again.
At the moment, I'm stuck trying to get the tooltip to show to the top-right of the mouse. I don't even know where to begin detecting if it would be in the viewport. Can anyone point me in the right direction?
$('p').on('mouseenter', function(e) {
$(tt).css('top', e.pageY - $(tt).css('height'));
$(tt).css('left', e.pageX);
$(tt).appendTo('body');
}).on('mousemove', function(e) {
$(tt).css('top', e.pageY - $(tt).css('height'));
$(tt).css('left', e.pageX);
}).on('mouseleave', function(e) {
$(tt).detach();
});
Example on JSFiddle
There are many different ways to handle tooltips, especially when using jQuery. This method probably would not have been my first choice. However, the following changes should work how you intended.
var tt = document.createElement('div');
tt.id = "tt";
$('p').on('mouseenter', function(e) {
var curPos = $( this ).offset().top - $( window ).scrollTop();
var inView = (curPos < 250) ? 0 : 250;
$(tt).css('top', e.pageY - inView);
$(tt).css('left', e.pageX);
$(tt).append($( this ).attr("data-myId"));
$(tt).appendTo('body');
}).on('mousemove', function(e) {
$(tt).css('top', e.pageY - $(tt).css('height'));
$(tt).css('left', e.pageX);
}).on('mouseleave', function(e) {
$(tt).empty($( this ).attr("data-myId"));
$(tt).detach();
});
Full changes in JSFiddle.
I am taking advantage of jQuery's offset() and scrollTop() methods to estimate the position of the current element within the viewable area of the document.
According to jQuery's API documentation, the .offset() method
allows us to retrieve the current position of an element relative to
the document. The documentation also states that the vertical
scroll position (.scrollTop()) is the same as the number of pixels that are hidden
from view above the scrollable area.
We use both of these methods to our advantage and subtract the number of pixels above the scrollable area from the current position of the element relative to the document. One important thing to note is that the offset method returns an object with the properties top and left.
var curPos = $( this ).offset().top - $( window ).scrollTop();
Since you had the #tt id set to a static 250px height, we can check if the current element position relative to the viewable portion of the window is less than 250. If it is, then we subtract nothing and let the tool tip sit below the mouse position. If it is greater than 250 then we subtract 250px and the tool tip will be above the current mouse position.
I am not sure how you were intending to pull in the content for the tool tips, but I also added $(tt).append($( this ).attr("data-myId")); to use the data-myId value as the tool tip content and $(tt).empty($( this ).attr("data-myId")); to clear it on mouseleave. I hope this helps!
Related
I'm attempting to have the element clicked being positioned automatically at the center of the screen. The list is having a horizontal scroll with some overflow-x : scroll which is hiding what's outside of the div(screen).
I can't find out what coordinates to pass to scrollLeft().
$('#timepicker li').on('click',function(){
var maxScrollLeft= $("#timepicker").scrollLeft('#timepicker').prop('scrollWidth') - $("#timepicker").width();
$('#timepicker').animate({
scrollLeft:
});
});
Please see my codepen: codepen
thank you.
Its a little tricky, but here's the solution.
var left = $(this).offset().left
var width = $("#timepicker").width();
var diff = left - width/2
$("#timepicker").scrollLeft($("#timepicker").scrollLeft()+diff)
Basically what i've done is get the present left position of the clicked element and divide it with half of the width of the container. This gives the difference which the scroller has to move in order to take the elment to the middle. Hope you understood the logic.
Here's the codepen attached
http://codepen.io/prajnavantha/pen/eNwWgx
You can copy paste this in the code pen click handler and see it working.
try this
$('#timepicker li').on('click',function(){
var pos=$(this).position().left; //get left position of li
var currentscroll=$("#timepicker").scrollLeft(); // get current scroll position
var divwidth=$("#timepicker").width(); //get div width
pos=(pos+currentscroll)-(divwidth/2); // for center position if you want adjust then change this
$('#timepicker').animate({
scrollLeft: pos
});
});
In this Fiddle, I made the red container draggable. As you can see, this is working fine but when the green container (parent container) is scrolled a bit and then the red container is dragged, the dragging is not happening at correct position.
Can someone please tell me what could be the problem?
I tried e.pageX, e.clientX and e.offsetX but still couldn't able to fix this. (or maybe I missed something)
You need to add the scrolling top position to your shape. If you want your square stay on the correct position check that:
function repositionShape(e) {
$self = repositionStart.self;
$commentSection = repositionStart.commentSection;
var dy = $('.wrapper').scrollTop(); // Get wrapper scroll position
$self.css({
'left': e.clientX - repositionStart.offset.left,
'top': e.clientY - repositionStart.offset.top +dy // Add delta to your square position
});
}
This effort is in response to my previously un-answered question: Resizable div doesn't stay within containment parameter
Since my resizable div, which is referred to as a pocket, is not the direct child of the container that I want it contained in, I supplied a callback in the resize method that should contain it within the container.
Fiddle here: http://jsfiddle.net/dKuER/12/
My Problem
When you re-size the resizable div to the left (which affects its left position) past the grid boundary, it does not always respect my logic in the callback function. As you drag to the left, you'll notice a blinking action, where the div will switch between its hard-coded left position to the left position determined by the mouse.
Depending on when you discontinue dragging, the left position of the div may either be at the hard-coded position or wherever the mouse stopped dragging.
How do I make sure the callback function's logic is ALWAYS respected?
// Relevant Code
// No blinking action when dealing with the width
//Re-sizing to the right works
if ( (pocketLeft + currentWidth) > (gridLeft + gridWidth) ) {
var deltaWidth = (gridLeft + gridWidth) - (pocketLeft + originalWidth);
ui.size.width = originalWidth -deltaWidth;
}
// This should force the position if the div is re-sized
// past the grid's left boundary
if (pocketLeft < gridLeft) {
ui.position.left = -120;
}
Using the mouse coordinates, and the width attained through the resizable div's object methods ( so obvious! ), rather than deriving it from some obscure calculations, I was able to achieve the correct effect
http://jsfiddle.net/dKuER/16/
var x = event.pageX - $('#grid').offset().left;
var y = event.pageY - $('#grid').offset().top;
if (x < 0)
{
ui.size.width = $(this).width();
ui.position.left = $(this).position().left;
}
I achieved this solution trying to understand the core of the jquery.ui.resizable code. However, I maintain there is more acceptable answer than mine.
Simple, I just would like to have it so when a user is dragging an item and they reach the very bottom or top of the viewport (10px or so), the page (about 3000px long) gently scrolls down or up, until they move their cursor (and thus the item being dragged) out of the region.
An item is an li tag which uses jquery to make the list items draggable. To be specific:
../jquery-ui-1.8.14.custom.min.js
http://code.jquery.com/jquery-1.6.2.min.js
I currently use window.scrollBy(x=0,y=3) to scroll the page and have the variables of:
e.pageY ... provides absolute Y-coordinates of cursor on page (not relative to screen)
$.scrollTop() ... provides offset from top of page (when scroll bar is all the way up, it is 0)
$.height()... provides the height of viewable area in the user's browser/viewport
body.offsetHeight ... height of the entire page
How can I achieve this and which event best accommodates this (currently its in mouseover)?
My ideas:
use a an if/else to check if it is in top region or bottom, scroll up if e.pageY is showing it is in the top, down if e.page& is in bottom, and then calling the $('li').mouseover() event to iterate through...
Use a do while loop... this has worked moderately well actually, but is hard to stop from scrolling to far. But I am not sure how to control the iterations....
My latest attempt:
('li').mouseover(function(e) {
totalHeight = document.body.offsetHeight;
cursor.y = e.pageY;
var papaWindow = window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
var iterate = 0;
do {
papaWindow.scrollBy(0, 2);
iterate++;
console.log(cursor.y, $pxFromTop, $userScreenHeight);
}
while (iterate < 20);
});
Works pretty well now, user just needs to "jiggle" the mouse when dragging items sometimes to keep scrolling, but for scrolling just with mouse position its pretty solid. Here is what I finally ended up using:
$("li").mouseover(function(e) {
e = e || window.event; var cursor = { y: 0 }; cursor.y = e.pageY; //Cursor YPos
var papaWindow = parent.window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
if (cursor.y > (($userScreenHeight + $pxFromTop) / 1.25)) {
if ($pxFromTop < ($userScreenHeight * 3.2)) {
papaWindow.scrollBy(0, ($userScreenHeight / 30));
}
}
else if (cursor.y < (($userScreenHeight + $pxFromTop) * .75)) {
papaWindow.scrollBy(0, -($userScreenHeight / 30));
}
}); //End mouseover()
This won't work as the event only fires while you're mouse is over the li.
('li').mouseover(function(e) { });
You need to be able to tell the position of the mouse relative to the viewport when an item is being dragged. When the users starts to drag an item attach an 'mousemove' event to the body and then in that check the mouse position and scroll when necessary.
$("body").on("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
Dont forget to remove your event when the user stops dragging.
$("body").off("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
This may not be exactly what you want, but it might help. It will auto-scroll when the mouse is over the 'border of the screen' (a user defined region). Say you have a 40px wide bar on the right of the screen, if the mouse reaches the first 1px, it will start scrolling. Each px you move into it, the speed will increase. It even has a nice easing animation.
http://www.smoothdivscroll.com/v1-2.htm
I get a weekly newsletter (email) from CodeProject, and it had some stuff that certainly looks like it will solve my problem... hopefully this can help others:
http://johnpolacek.github.com/scrollorama/ -- JQuery based and animates the scroll
https://github.com/IanLunn/jQuery-Parallax -- JQuery based, similar to above
http:// remysharp. com/2009/01/26/element-in-view-event-plugin/ -- JQuery, detects whether an element is currently in view of the user (super helpful for this issue!)
Also the site in #2 had some interesting code:
var windowHeight = $window.height();
var navHeight = $('#nav').height() / 2;
var windowCenter = (windowHeight / 2);
var newtop = windowCenter - navHeight;
//ToDo: Find a way to use these vars and my original ones to determine scroll regions
I am trying to create a small tooltip script that mostly relies on css. The bit of JavaScript I can't figure out is how to position the div based on its distance to the browsers edge.
When the div appears I would like it to check how close it is to the top, bottom, left and right. For example if there is not enough space to display the div above the tooltip link it should position it below the link.
Essentially I would like the div to be "aware" of its position and know where to go to make sure it is visible.
Thanks
I just had to write very similar code myself, for use with tipsy (so my solution uses jQuery). Here's the basic math, assuming <div id="mydiv">...</div> is the div you're working with. I account for the div's height and width when measuring the distances to the right and bottom edges as well.
dTop, dBottom, dLeft, and dRight are the distance from the div's top, bottom, left, and right edges, respectively, to the same edge of the viewport. If you want to measure based on the upper-left corner of the div, don't subtract dTop or dLeft when computing dBottom and dRight.
var $doc = $(document),
$win = $(window),
$this = $('#mydiv'),
offset = $this.offset(),
dTop = offset.top - $doc.scrollTop(),
dBottom = $win.height() - dTop - $this.height(),
dLeft = offset.left - $doc.scrollLeft(),
dRight = $win.width() - dLeft - $this.width();
See Measuring Element Dimension and Location for help
This cheat sheet for the Prototype library has a good example.