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.
Related
I'm building a Pinterest type board plugin with jQuery, where I'm having difficulty figuring out how they position their modules.
Below is a snippet of how each element is being placed per their nth-value in the HTML. But this isn't right because Pinterest positions elements that go to the next row underneath the shortest column. Quite like this pen here, http://codepen.io/nikhilkumar80/pen/oxpXVK, but I found it difficult to understand.
function modPosition() {
$this.find(".pinterest-board__mod").each(function( modIndex ) {
$(this).css({
position: "absolute",
left: columnWidth * (modIndex % settings.columns) + "%",
width: columnWidth + "%"
});
// ..........
});
}
modPosition();
Here's my CodePen link, http://codepen.io/joshuawaheed/pen/beeJKq?editors=0010
I'm also having difficulties figuring out how to set the elements top position.
What can I do to make this work? I've put this in a function so that the positioning can run it again on document resize and when a user clicks on a filter option to remove the elements and append the appropriate modules from the appropriate array. The plugin is also set to determine module widths based on the options columns value.
Thank you in advance.
You can implement it in several ways
I suggest you two ways
1) you can use one of the js modules
You can read more about it there
https://designshack.net/articles/css/masonry/
http://www.wtfdiary.com/2012/08/6-amazing-jquery-plugins-to-design.html
2) You can use css rules(flexbox)
You can read more about it there
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
Both of these methods have positive and negative traits
For example fleksboks is not supported by all versions of the browser
But JS is more load the processor
I've got it working. I solved this by:
Creating an array, its lengt equal to the column count.
Storing the height value of modules in the first row in the array.
Looping through each module.
Injecting the smallest array value as css position top for the current module.
Adding the height of the current module with the array item containing the smallest value.
Setting the position left value by dividing 100% with the index of of the smallest value in the array.
Here is the code I wrote, which you can view and fork by following this link
function modPosition() {
var columnsHeight = [/* Length equal to column count */], // This will be recreated on window resize.
columnCount = /* Column count value */;
/* Set CSS position top and left. */
function modCssTopLeft() {
var columnIndex = 0;
$this.find(".pinterest-board__mod").each(function( modIndex ) {
var topPos = 0,
leftPos = 0;
if ( modIndex >= columnCount) {
topPos = Math.min.apply( Math, columnsHeight ); // Get smallest value in array.
leftPos = 100 * columnsHeight.indexOf(topPos) / columnCount; // Set left position based on column count.
columnsHeight[columnsHeight.indexOf(topPos)] += $(this).outerHeight(); // Change arrays smallest value by adding it with current modules height.
}
else {
leftPos = 100 * (modIndex++) / columnCount; // Positioning for the modules in the first row.
}
$(this).css({
position: "absolute",
top: topPos + "px",
left: leftPos + "%"
});
$(this).closest(".pinterest-board__content").css({
height: Math.max.apply( Math, columnsHeight ) // Set height to the modules parent container.
});
});
}
modCssTopLeft();
}
modPosition();
$(window).resize(function() {
modPosition();
});
The function getBoundingClientRect() can return non-integer values. For example, something like:
<div style="position: relative; left: 5%; width: 66.666%"></div>
almost always have non-integer values for the left and width values of getBoundingClientRect . You can see this at http://plnkr.co/edit/QW91gy3hPMagSECQswdM?p=preview , with an example value of its left value being 32.796875 (in Chrome at least).
How these non-integer values are actually rendered on the screen I believe is browser-dependent.
So, how can I programatically find the whole-pixel coordinates of an element on-screen?
Edit: ideally without jQuery, and ideally without walking the DOM.
a lot of modern browsers use subpixel rendering, so most likely there exist no whole-pixel coordinates..
but with jQuery you can do something like this to get an array [left, top, width, height] relative to document space:
function bounds(el) {
var $el = $(el);
if (!$el.is(':visible')) {
return null;
}
var offset = $el.offset();
return [offset.left, offset.top, $el.outerWidth(), $el.outerHeight()];
}
relative to Viewport:
function boundsVp(el) {
var $el = $(el);
if (!$el.is(':visible')) {
return null;
}
var $win = $(window);
var offset = $el.offset();
return [offset.left - $win.scrollLeft(), offset.top - $win.scrollTop(), $el.outerWidth(), $el.outerHeight()];
}
you might be interested in jQuery.fracs as well..
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.
I'm trying to set the scroll position on a page so the scroller is scrolled all the way to the top.
I think I need something like this but it's not working:
(function () { alert('hello'); document.body.scrollTop = 0; } ());
Any ideas?
You can use window.scrollTo(), like this:
window.scrollTo(0, 0); // values are x,y-offset
Also worth noting window.scrollBy(dx,dy) (ref)
Note that if you want to scroll an element instead of the full window, elements don't have the scrollTo and scrollBy methods. You should:
var el = document.getElementById("myel"); // Or whatever method to get the element
// To set the scroll
el.scrollTop = 0;
el.scrollLeft = 0;
// To increment the scroll
el.scrollTop += 100;
el.scrollLeft += 100;
You can also mimic the window.scrollTo and window.scrollBy functions to all the existant HTML elements in the webpage on browsers that don't support it natively:
Object.defineProperty(HTMLElement.prototype, "scrollTo", {
value: function(x, y) {
el.scrollTop = y;
el.scrollLeft = x;
},
enumerable: false
});
Object.defineProperty(HTMLElement.prototype, "scrollBy", {
value: function(x, y) {
el.scrollTop += y;
el.scrollLeft += x;
},
enumerable: false
});
so you can do:
var el = document.getElementById("myel"); // Or whatever method to get the element, again
// To set the scroll
el.scrollTo(0, 0);
// To increment the scroll
el.scrollBy(100, 100);
NOTE: Object.defineProperty is encouraged, as directly adding properties to the prototype is a breaking bad habit (When you see it :-).
... Or just replace body by documentElement:
document.documentElement.scrollTop = 0;
If you want to set the scroll position of document.body, you can scroll the entire window altogether using window.scrollTo(); it takes either a pair of coordinates (x,y) or an options object – if you just want to scroll nicely to the top, try window.scrollTo({top:0,behavior:'smooth'});.
However, in some instances, you have an element to scroll (and not the entire document). For that case, elements also provide a scrollTo() method using the same arguments.
document.querySelector('ul#list').scrollTo(0,0);
Tracing this jquery autocomplete function, can someone explain in detail what is going on here?
function showResults() {
// get the position of the input field right now (in case the DOM is shifted)
var pos = findPos(input);
// either use the specified width, or autocalculate based on form element
var iWidth = (options.width > 0) ? options.width : $input.width();
// reposition
$results.css({
width: parseInt(iWidth) + "px",
top: (pos.y + input.offsetHeight) + "px",
left: pos.x + "px"
}).show();
};
It uses this function:
function findPos(obj) {
var curleft = obj.offsetLeft || 0;
var curtop = obj.offsetTop || 0;
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
curtop += obj.offsetTop
}
return {x:curleft,y:curtop};
}
Reference: http://www.pengoworks.com/workshop/jquery/lib/jquery.autocomplete.js
offsetLeft and offsetTop are properties that describe how many pixels obj is offset from it's containing element. What this function does is:
Compute the offset of obj from its parent element and save these values in variables
Set obj to be the parent element of the item last computed from
Goto 1. Repeat until you have reached the top level of the DOM.
This calculates how many pixels that obj is from the top and left sides of the rendered page.
Basically, it's figuring out the X and Y coordinates (left and top in CSS terms) of the input field you're using autocomplete on and setting the top and left CSS attributes of the autocomplete HTML to have it appear there. In other words, it's matching up the corners of the input Element and autocomplete layer so they appear at the same place (it's doing the same with widths and heights, too).
In the findPos function, we're basically walking back up the DOM tree getting the offsets (see Mozilla's dev center) of each Element from their parent (and eventually the body tag) to get the precise x and y coordinates of that input so that we can position the autocomplete layer at it's coordinates. We sum these, and wind up with the x and y values we pass back up to use in setting the left and top positions in CSS.
It's essentially copying the x and y position, height, and width of your input and applying them to the autocomplete layer so that they match up visually.