I am trying to extend the jQuery UI dialog() to use arrow pointers to point to what was clicked. The issue I've run into is knowing when the collision method runs so I can change to pointers from the left side to the right side.
Is it possible to know when the position.collision method is triggered?
$('#myElem').dialog({
position:{
collision:'flip'
}
});
Solution:
As it turns out you can pass more than they say in the documentation. Here is what I ended up using that solved my problem:
position:
{
my: 'left top',
at: 'right center',
of: $trigger,
offset: '20 -55',
collision: 'flip',
using: function(obj) {
var $modal = $(this),
trigger_l = $trigger.position().left,
modal_l = obj.left,
top;
// Check IE's top position
top = ( isIE ) ? obj.top - 48 : top = obj.top;
$(this).css({
left: obj.left + 'px',
top: top + 'px'
});
}
}
I used the using method inside the position object to do the majority of the work. I then did a quick check to see if it's IE, done earlier in the document, and set my CSS accordingly.
I did this a while ago so let me know if you run into problems. :)
Don`t know how your solution could help, but this is actually close to the real solution. We need use the same "using" function, which recieves two arguments. The first one is actual coords of the positioned object, and we will need to manually set this coords to the positioned object, like you did in your solution. But to determine the direction of the flip-collision we need to use second argument. This argument provides feedback about the position and dimensions of both elements, as well as calculations to their relative position. You can read about this here.
If you have horizontal pointing arrow and you need to switch it direction from left to right and vice versa according to the current collision, you can get the value of "horizontal" property from the second argument to the "using" function. The "left" value of this property means that positioned object positioned to the right of the target, and vice versa. So you can change classes on the positioned element accordingly to current collision. Here is example:
position:
{
my: 'left top',
at: 'right center',
of: $trigger,
offset: '20 -55',
collision: 'flip',
using: function(coords, feedback) {
var $modal = $(this),
top = ( isIE ) ? coords.top - 48 : coords.top,
className = 'switch-' + feedback.horizontal;
$modal.css({
left: coords.left + 'px',
top: top + 'px'
}).removeClass(function (index, css) {
return (css.match (/\bswitch-\w+/g) || []).join(' ');
}).addClass(className);
}
}
Note that in example above we removed from the $modal any 'switch-' classes added earlied. And then added current 'switch-' class. So any time you will be position your modal, it will have 'switch-left' or 'switch-right' class depending on current collision.
Use qTip instead.
Related
I am using the following code (Javascript within a webpage) to create a 'new' element in the DOM dynamically. I wish to position this say 200px 'below' an existing element. However my output has the positioning of the new element(s) all wrong...as if the position (top, left) I am specifying is ignored.
var _reference = document.getElementById("outputs");
for (_count = 0; _count < _limits; _count++) {
var _structure = document.createElement("div");
_structure.setAttribute("class", "container-fluid");
_structure.setAttribute("id", "struct_" + _tally);
if (_count === 0){
_rect = _reference.getBoundingClientRect();
//get the bounding box of the "outputs" id element...
document.getElementById("outputs").appendChild(_structure);
_structure.style.top = _rect.top + "200px"; //NOT positioned 200px below 'outputs'
_structure.style.left = _rect.left; //NOT positioned same position as 'outputs'
} //_count is "0"
} //for loop
I would have thought this should be fairly straightforward...however it is driving me crazy...any help appreciated.
You'll need to set _structure.style.position to 'relative', 'absolute', 'fixed', or 'sticky' in order to use top, left, right, bottom.
You need to set your position to realtive or absolute in order for this to work, also note that position: absolute sets the position according to the nearest relative positioned parent while position: relative positions according to the current position of the element
So I am trying to show a tooltip like box as I scroll my webpage and I would like it to follow the scrollbar along the right side of the page.
I looked around and found something to attempt to accomplish that as shown below:
function returnPercentHeight(){
var a = document.getElementById('rightPanel').scrollTop;
var b = document.getElementById('rightPanel').scrollHeight - document.getElementById('rightPanel').clientHeight;
return ((a/b) * 100);
}
I then append a % to the end and set the top margin of the tooltip to that returned value. This works pretty well (sort of) I have to adjust the return((a/b) * x) part (x) to make it follow the scrollbar based on the size of the browser window. Is there a better way to accomplish what I am trying to do? (NOTE: I can only use javascript, no JQuery please.)
EDIT:
Only the div given an ID of 'RightPanel' is scrolling, I am not using the scrollbar on the browser, but a scrollbar on an inner div.
There are three ways to do so:
First:
is to use the fixed position as following;
Position: Fixed;
Second:
With jQuery;
$(function(){
$(window).on('scroll', function() {
var scrollPOS = $(document).scrollTop();
$('.scroll').css({
top: scrollPOS
});
}).scroll();
});
Third:
Same as the previous, only animated;
$(window).on('scroll', function() {
$("#div").stop().animate({
"marginTop": ($(window).scrollTop()) + "px",
"marginLeft":($(window).scrollLeft()) + "px"}, "slow" );
});
Although IE doesn't support, this is the coolest I've seen:
// get
var x = window.scrollX,
y = window.scrollY;
// set
window.scrollTo(1, 2);
As per Jquery API documentation:
.position()Returns: Object
Description: Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.
This method does not accept any arguments.Reference here
But somewhere i found using this:
$("#position1").position({
my: "center",
at: "center",
of: "#targetElement"
});
An object has been passed to position method .Isn't this against API documentation?It seems that the properties passed to an object above has some special meaning.What are those properties stating .What they do?I m a complete beginner to jquery.So may be i m wrong .
This variant of .position() is part of the jQuery UI position utility. It gives you an easy way to place an element relative to another one (or the mouse cursor) in a certain way.
You are totally right that the original position() method does not accept arguments... but:
This plugin extends jQuery's built-in .position() method. If jQuery UI is not loaded, calling the .position() method may not fail directly, as the method still exists. However, the expected behavior will not occur.
Check this out - http://docs.jquery.com/UI/API/1.8/Position
That feature is in jqueryUI position utility not in Core jQuery
Let's take it to the codez ! A quick glance into the jQuery 1.9.1 source reveals:
position: function() {
if ( !this[ 0 ] ) {
return;
}
var offsetParent, offset,
parentOffset = { top: 0, left: 0 },
elem = this[ 0 ];
// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
if ( jQuery.css( elem, "position" ) === "fixed" ) {
// we assume that getBoundingClientRect is available when computed position is fixed
offset = elem.getBoundingClientRect();
} else {
// Get *real* offsetParent
offsetParent = this.offsetParent();
// Get correct offsets
offset = this.offset();
if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
parentOffset = offsetParent.offset();
}
// Add offsetParent borders
parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
}
// Subtract parent offsets and element margins
// note: when an element has margin: auto the offsetLeft and marginLeft
// are the same in Safari causing offset.left to incorrectly be 0
return {
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
};
},
No arguments read, no arguments used. Wherever you saw that code, its not jQuery core. Most likely, its because the original author used the jQuery UI, which extends that method.
As per the jQuery API for the Position
my: Defines which position on the element being positioned to align
with the target element.
at: Defines which position on the target element to align the positioned element against,
of: Is for the element to position against. If you provide a selector, the first matching element will be used. Example: "#targetElement" in your case.
OK, here is my question.
Using jQuery UI position. It is possible to position an element in relation to another element on the screen. It sets the left and top css properties on the element being positioned which positions it on the screen.
What I want to do is instead of setting the left and top, I want to possibly set right and bottom instead so that if the positioned element grows or shrinks, it will grow / shrink in the correct direction.
Let me go into details.
Ok, what I want is if an element is positioned on it's right, then I want to set the right css property instead of the left and if an element is positioned on its bottom, then I want to set bottom instead of top. I can do this using the using property of jQuery UI Position, but I run into problems with collision detection. If collision detection is set to flip and the element gets flipped, I want to detect this and figure out whether I need to set right instead of left and bottom instead of top. Check out the code below to get a better idea of what I'm trying to do.
$('#somediv').position({
my: 'right bottom',
at: 'right top',
of: $('#someotherdiv'),
offset: '0 5',
collision: 'flip flip',
using: function(pos) {
// Figure out the right and bottom css properties
var right = $(window).width() - pos.left - $(this).outerWidth(true);
var bottom = $(window).height() - pos.top - $(this).outerHeight(true);
// Position the element so that right and bottom are set.
$(this).css({left: '', right: right, top: '', bottom: bottom});
}
});
That works great, except when the div gets flipped from collision detection. If it gets flipped horizontally, I want to set left instead of right and if it gets flipped vertically I want to set top instead of bottom.
The ideal solution would be if there was a way to tell (in the using function) whether the element was flipped and in what directions. So, anyone have any ideas to figure out whether an element was flipped using collision detection?
OK, figured it out.... Here is my attempt to explain how I made it work.
What you have to do is call position again within the using function. Call it once without collision detection and once with collision detection. If the position changes, then it was flipped. Here is some example code with comments.
$('#somediv').position({
my: 'right bottom',
at: 'right top',
of: $('#someotherdiv'),
offset: '0 5',
collision: 'flip flip',
using: function (pos1) {
// OK, we got a position once inside the pos1 variable,
// let's position it again this time without collision detection.
$(this).position({
my: 'right bottom',
at: 'right top',
of: $('#someotherdiv'),
offset: '0 5',
collision: 'none none',
using: function(pos2) {
var hpos = 'right';
var vpos = 'bottom';
// Check to see if it was flipped horizontal
if (pos1.left != pos2.left) {
/* It was flipped horizontally so position is now
my: 'left bottom',
at: 'left top'
*/
hpos = 'left';
}
// Check to see if it was flipped vertical
if (pos1.top != pos2.top) {
/* It was flipped vertically */
vpos = 'top';
}
// Figure out the right and bottom css properties
var right = $(window).width() - pos1.left - $(this).outerWidth(true);
var bottom = $(window).height() - pos1.top - $(this).outerHeight(true);
// Set the horizontal position
if (hpos == 'right') {
$(this).css({left: '', right: right});
} else {
$(this).css({left: pos1.left, right: ''});
}
// Set the vertical position
if (vpos == 'bottom') {
$(this).css({top: '', bottom: bottom});
} else {
$(this).css({top: pos1.top, bottom: ''});
}
}
});
}
});
If anyone has a more efficient idea, please let me know. Thanks.
I'm a bit stumped here. I am developing a feedback utility that will allow the user to "draw" boxes on a web page to highlight problem areas. Right now I have an overlay DIV that fills the screen and jQuery allows you to draw red outlined DIVs by clicking and dragging.
Here is the JS:
{
var $feedbackOverlay = jQuery('#feedbackOverlay');
var $original = { top: 0, left:0 };
$feedbackOverlay.bind('mousedown', function (e)
{
jQuery('<div id="currentHighlight"></div>')
.css('width', '1px')
.css('height', '1px')
.css('border', 'solid 3px #ff0000')
.css('border-radius', '5px')
.css('position', 'absolute')
.css('left', e.pageX)
.css('top', e.pageY)
.css('z-index', '8000001')
.appendTo('body');
$original = { top: e.pageY, left: e.pageX };
});
$feedbackOverlay.bind('mousemove', function (e)
{
var $currentHighlight = jQuery('#currentHighlight');
if ($currentHighlight.length > 0)
{
var $pos = { top: e.pageY, left: e.pageX };
if($pos.top < $original.top) $currentHighlight.css('top', $pos.top);
if ($pos.left < $original.left) $currentHighlight.css('left', $pos.left);
$currentHighlight.height(Math.abs($pos.top - $original.top));
$currentHighlight.width(Math.abs($pos.left - $original.left));
}
});
$feedbackOverlay.bind('mouseup', function (e)
{
var $currentHighlight = jQuery('#currentHighlight');
$currentHighlight.removeAttr('id');
});
var $feedbackInstructions = jQuery('#feedbackInstructions');
$feedbackInstructions.fadeIn(1000, function ()
{
setTimeout(function ()
{
$feedbackInstructions.fadeOut(1000);
}, 3000);
});
$feedbackOverlay.height(jQuery(document).height());
});
Here is a jsFiddle for the above:
http://jsfiddle.net/Chevex/RSYTq/
The problem is that I can't drag the boxes up or left. The first click puts the top left corner where the mouse clicked. After that subsequent dragging will change the width of the box. Letting go of the mouse completes the box and you may then start drawing another one. If you try to drag the DIV left or up while drawing it's width will remain at 0 but won't go negative.
Here you can find working solution: http://jsfiddle.net/RSYTq/34/
Something like this will get you closer to what you want: http://jsfiddle.net/RSYTq/18/
Doesn't quite handle move up and to the left and then switching to moving down and to the right quite right yet but it gives you the idea.
There's no such thing a a negative width - these are not coorindinates. You need to reposition and recalculate the corner positions relative to the corner that's not being moved.
Sounds like you need to check if the click origin (x,y) is > than the current mouse position, and then swap which one you use for the CSS top-left.
You would need to track the original start point somewhere (variables, data attributes on #currentHighlight, wherever you want), and check for width or height < 0. When so, set the #currentHighlight left/top CSS to be offset by original + (e.pageX - $currentHighlight.position().left) (for example). Then set the #currentHighlight width/height to the same difference (but positive: (e.pageX - $currentHighlight.position().left) * -1).