jQuery UI strange resize behaviour - javascript

I have a div which is resizable from the left (w) and the right (e) using jQuery UI. Resizing on the right works perfectly, but on the left two things behave different:
I can't resize the element to 0 width
It jumps when resizing starts
I made this fiddle
$("#test").resizable({
handles: 'e,w',
grid: 32,
maxWidth: null,
minWidth: 0
});
Why is that so?
Thanks
Edit
Grid 32 is needed, but you are right, it would work without.

Remove grid: 32. It causes the problem you are facing.

I found a solution.
I overwrite jQuery UI's $.ui.plugin.add("resizable", "grid") on resize start.
Not the best solution I think but it works.
Here you can see the changes I made in the last if-else:
Old:
if ( newWidth - gridX > 0 ) {
that.size.width = newWidth;
that.position.left = op.left - ox;
} else {
that.size.width = gridX;
that.position.left = op.left + os.width - gridX;
}
Customised:
if ( newWidth - gridX >= 0 ) {
that.size.width = newWidth;
that.position.left = op.left - ox;
} else {
that.size.width = o.minWidth;
that.position.left = op.left + os.width - gridX;
}

Related

Remove function on browser width

I'm still very new to javascript and I'm learning as I build. This may be a simple fix but how would I disable a function on my parallax images ( or disable a specific js function in general ) on a smaller width?
Here's what I have so far that doesn't quite work but shows "undefined". I've been searching for a solution for a couple of days now with no luck. Any help would be appreciated.
var paraLlaxS = document.querySelector("#firstImgc2");
var paraLlaxS = document.querySelector("#secondImgc2");
var paraLlaxS = document.querySelector("#backbox1");
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + ", " + yPos + "px, 0)";
}
window.addEventListener("DOMContentLoaded", scrollLoop, false);
var xScrollPosition;
var yScrollPosition;
function scrollLoop() {
xScrollPosition = window.scrollX;
yScrollPosition = window.scrollY;
setTranslate(0, yScrollPosition * -0.2, firstImgc2);
setTranslate(0, yScrollPosition * 0.15, secondImgc2);
setTranslate(0, yScrollPosition * -0.6, backbox1);
requestAnimationFrame(scrollLoop);
if(window.innerWidth < 900) {
document.querySelector('#firstImgc2').innerHTML = window.removeEventListener("DOMContentLoaded", scrollLoop, false);
return;
} else {
}
}
You could add a conditional return at the beginning of you function. But if the width increases again you would need to listen for that to start the loop again.
function scrollLoop() {
if(window.innerWidth < 900)return;
...
I borrowed a solution from another post.
Listen for browser width for responsive web design?
This code is compatible with a wider variety of browsers as getting the screen size can vary depending on the browser.
var width = 0;
function getWindowSize() {
if (document.body && document.body.offsetWidth) {
width = document.body.offsetWidth;
}
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
width = document.documentElement.offsetWidth;
}
if (window.innerWidth) {
width = window.innerWidth;
}
return(width);
}

jquery draggable containment array values for scaled container

If anyone could help me figure out how to make the draggable elements contained in a div that changes scale based on window size, i'd really appreciate any guidance.
If I do:
element.draggable({
cursor: "move",
containment: '#container'
});
What will happen is it gives me the containment for the regular size of the container. So if I have a transform: scale(1.5), there will be space in the container that the draggable element can not go.
I've also tried containment: 'parent' but that get's very glitchy.
EDIT
I've found out how to get the top and left containment but I can't figure out how to get the right and bottom.
var containmentArea = $("#container");
containment: [containmentArea.offset().left, containmentArea.offset().top, ???, ???]
I've tried width and height from containmentArea[0].getBoundingClientRect() but that doesn't seem to be the right move either.
Here is a jsfiddle of some example code.
A version with resetting the coordinates in the drag event (since they were being recalculated already for the scale transformations), without using the containment:
var percent = 1, containmentArea = $("#container");
function dragFix(event, ui) {
var contWidth = containmentArea.width(), contHeight = containmentArea.height();
ui.position.left = Math.max(0, Math.min(ui.position.left / percent , contWidth - ui.helper.width()));
ui.position.top = Math.max(0, Math.min(ui.position.top / percent, contHeight- ui.helper.height()));
}
$(".draggable").draggable({
cursor: "move",
drag: dragFix,
});
//scaling here (where the percent variable is set too)
Fiddle
In the example width and height of the container are obtained inside the dragevent, you could also store them when scaling for better performance. By having them calculated inside the event, they still work after rescaling, although the percent variable still has to be set. To be truly generic, it could be obtained inside the event as well (and instead of a fixed container, ui.helper.parent() could be used)
Since the offset inside the dragevent is (0,0) related to the container (at least it is for the current setup), took the liberty of simplifying originalleft + (position - originalposition)/percent to position / percent
Start offset didn't seem to be necessary any more, so left it out in the fiddle, but can be re-added if needed.
Take a look to this :
http://jsfiddle.net/z0gqy9w2/3/
The edited code is the following one :
// Matrix regex to take the scale value property of $('#container') element
var matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/,
matches = $('#container').css('transform').match(matrixRegex);
// Matches have this value : ["matrix(1.5, 0, 0, 1.5, 0, 0)", "1.5", "1.5"] , so we need matches[1] value :
var scaleValue = matches[1];
$(".draggable").draggable({
cursor: "move",
start: startFix,
drag: dragFix,
containment: [containmentArea.offset().left, containmentArea.offset().top,
( ( containmentArea.offset().left + ( containmentArea.width() * scaleValue ) ) - ( $(".draggable").width() * scaleValue ) ) ,
( ( containmentArea.offset().top + ( containmentArea.height() * scaleValue ) ) - ( $(".draggable").height() * scaleValue ) ) ]
});
As you see, here is the trick :
( ( containmentArea.offset().left + ( containmentArea.width() * scaleValue ) ) - ( $(".draggable").width() * scaleValue ) )
Your right max position will be : The main container left offset + the true width of the container ( with scale ) - the item true width (to let it inside the container).
(Tip: Be free to change the "percent" var value as you want too see the results)
regex ref
Here is my solution:
var _zoom = 1.2,
$element = $('.draggable-element'),
$container = $('#container');
var containmentW,
containmentH,
objW,
objH;
$element.draggable({
start: function(evt, ui) {
ui.position.left = 0;
ui.position.top = 0;
containmentW = $container.width() * _zoom;
containmentH = $container.height() * _zoom;
objW = $(this).outerWidth() * _zoom;
objH = $(this).outerHeight() * _zoom;
},
drag: function(evt, ui) {
var boundReached = false,
changeLeft = ui.position.left - ui.originalPosition.left,
newLeft = ui.originalPosition.left + changeLeft / _zoom,
changeTop = ui.position.top - ui.originalPosition.top,
newTop = ui.originalPosition.top + changeTop / _zoom;
// right bound check
if(ui.position.left > containmentW - objW) {
newLeft = (containmentW - objW) / _zoom;
boundReached = true;
}
// left bound check
if(newLeft < 0) {
newLeft = 0;
boundReached = true;
}
// bottom bound check
if(ui.position.top > containmentH - objH) {
newTop = (containmentH - objH) / _zoom;
boundReached = true;
}
// top bound check
if(newTop < 0) {
newTop = 0;
boundReached = true;
}
// fix position
ui.position.left = newLeft;
ui.position.top = newTop;
// inside bounds
if(!boundReached) {
// do stuff when element is dragged inside bounds
}
}
});
Link to fiddle

parallax scrolling issue - div element jerking when scrolling in webkit browsers

I have created a parallax scroll, which seem to be working fine in firefox however in the chrome browser there's a slight jump on the body text when scrolling. click here scroll to the about section. I am not sure if t this is a css or JS issue.. below is a snippet i have incorporated into my parallax function
Does anyone know how i an fix this issue?
$(document).ready(function(){
// Cache the Window object
$window = $(window);
// Cache the Y offset and the speed of each sprite
$('[data-type]').each(function() {
$(this).data('offsetY', parseInt($(this).attr('data-offsetY')));
$(this).data('Xposition', $(this).attr('data-Xposition'));
$(this).data('speed', $(this).attr('data-speed'));
});
// For each element that has a data-type attribute
$('[data-type="background"]').each(function(){
// Store some variables based on where we are
var $self = $(this),
offsetCoords = $self.offset(),
topOffset = offsetCoords.top;
// When the window is scrolled...
$(window).scroll(function() {
// If this section is in view
if ( ($window.scrollTop() + $window.height()) > (topOffset) &&
( (topOffset + $self.height()) > $window.scrollTop() ) ) {
// Scroll the background at var speed
// the yPos is a negative value because we're scrolling it UP!
var yPos = -($window.scrollTop() / $self.data('speed'));
// If this element has a Y offset then add it on
if ($self.data('offsetY')) {
yPos += $self.data('offsetY');
}
// Put together our final background position
var coords = '50% '+ yPos + 'px';
// Move the background
$self.css({ backgroundPosition: coords });
$('[data-type="scroll-text"]', $self).each(function() {
var $text= $(this);
var pos = ($window.scrollTop()/10) * $text.data('speed');
var curP = $text.css('margin-top');
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
if(is_chrome) {
$text.animate({
paddingTop: pos,
}, 200, 'linear', function() {
// Animation complete.
});
} else {
$text.css('padding-top', pos);
}
});
}; // in view
}); // window scroll
}); // each data-type
}); // document ready
Some suggestions:
1.) Use position: fixed to avoid any jitter, as you'll be taking the element out of the document flow. You can then position it using z-index.
2.) Cache as much as you can to ease processing time.
3.) Math.round may not be necessary, but try adding this CSS to your moving areas: -webkit-transform: translate3d(0,0,0); This will force hardware acceleration in Chrome, which may ease some of the jittering. (It looked smoother on my screen when I added this with Inspector, but it didn't get rid of the jumpiness with the scroll wheel.) Note: Don't do this on your entire document (e.g. body tag), as it might cause some issues with your current layout. (Your navigation bar didn't stick to the top of the window, for instance.)
4.) If you have any animations running as part of your parallax logic (tweening the margin into place or something along those lines), remove it - that would probably cause the jump you see.
Hope this helps. Best of luck.
I see the same jittering in FireFox and Chrome (Mac). Looking at your containers, one thing that's glaring at me is the pixel position that's being calculated/used.
Chrome: <div id="about-title" style="margin-top: 1562.3999999999999px;">
FireFox: <div id="about-title" style="margin-top: 1562.4px;">
Browsers aren't going to allow content to sit at 1/2 pixel, let alone 0.3999999 of a pixel. I think it's moving it, and trying to calculate whether to round up or round down. It jitters because it's calculating with every click of your mouse wheel.
Thus, I'd try adding Math.round() to your positions so that the containers are never being left in limbo.
Take a look at the code here: http://webdesigntutsplus.s3.amazonaws.com/tuts/338_parallax/src/index.html
Firebug some of the elements, and you'll see that their only fraction of a pixel is '0.5'. Most of them (the bulk) go to round number values.
You are going to have to change the way that the scrolling works (i.e. change how the spacing is computed), but this can be fixed by adding the position:fixed CSS element to the page elements that are scrolling. The problem is coming from the time that it takes for the JavaScript to process and then render.
For example, on your page you would set each of the <div> tags containing text to have a fixed position and then use the JavaScript/JQuery function to update the top: CSS element. This should make the page scroll smoothly.
Have you tried adding the preventdefault inside the scroll function?
$(window).scroll(function(e) {
e.preventDefault();
// rest of your code
}
In a previous question I created a fairly good parallax scrolling implementation. Jquery Parallax Scrolling effect - Multi directional You might find it useful.
Here's the JSFiddle http://jsfiddle.net/9R4hZ/40/ use the up/down arrows or scroll wheel.
Using padding and margin for the positioning are probably why you're experiencing rendering issues. While my code uses scroll or keyboard input for the effect you can loop the relavent portion and check the $moving variable until you reach the desired element on screen.
function parallaxScroll(scroll) {
// current moving object
var ml = $moving.position().left;
var mt = $moving.position().top;
var mw = $moving.width();
var mh = $moving.height();
// calc velocity
var fromTop = false;
var fromBottom = false;
var fromLeft = false;
var fromRight = false;
var vLeft = 0;
var vTop = 0;
if($moving.hasClass('from-top')) {
vTop = scroll;
fromTop = true;
} else if($moving.hasClass('from-bottom')) {
vTop = -scroll;
fromBottom = true;
} else if($moving.hasClass('from-left')) {
vLeft = scroll;
fromLeft = true;
} else if($moving.hasClass('from-right')) {
vLeft = -scroll;
fromRight = true;
}
// calc new position
var newLeft = ml + vLeft;
var newTop = mt + vTop;
// check bounds
var finished = false;
if(fromTop && (newTop > t || newTop + mh < t)) {
finished = true;
newTop = (scroll > 0 ? t : t - mh);
} else if(fromBottom && (newTop < t || newTop > h)) {
finished = true;
newTop = (scroll > 0 ? t : t + h);
} else if(fromLeft && (newLeft > l || newLeft + mw < l)) {
finished = true;
newLeft = (scroll > 0 ? l : l - mw);
} else if(fromRight && (newLeft < l || newLeft > w)) {
finished = true;
newLeft = (scroll > 0 ? l : l + w);
}
// set new position
$moving.css('left', newLeft);
$moving.css('top', newTop);
// if finished change moving object
if(finished) {
// get the next moving
if(scroll > 0) {
$moving = $moving.next('.parallax');
if($moving.length == 0)
$moving = $view.find('.parallax:last');
} else {
$moving = $moving.prev('.parallax');
if($moving.length == 0)
$moving = $view.find('.parallax:first');
}
}
// for debug
$('#direction').text(scroll + " " + l + "/" + t + " " + ml + "/" + mt + " " + finished + " " + $moving.text());
}
May not be related to your specifics, but I had a jumpy parallax scrolling problem, I was able to solve it adding the following CSS for the fixed portions of the page:
#supports (background-attachment: fixed)
{
.fixed-background
{
background-attachment: fixed;
}
}
Not sure of all the specifics, but found at Alternate Fixed & Scroll Backgrounds

jquery scroll div only if parent is taller

How can I calculate the height of the parent so that the left div is only animated if there is empty space below itself. I have tried to calculate the parents height is greater then the question height + the margin-top.
This is a simplified version of the code: http://jsfiddle.net/rewsn/6/ as a example. Although in the real version the questions/answer are changed via AJAX so this is the reason I need to calculate the height each time.
If I understood correctly, then a simple condition like below should solve your problem.
if ((y + el.outerHeight()) < $container.height()) {
DEMO
var el = $('.answer');
var elpos = el.offset().top;
var $container = $('.container');
$(window).scroll(function() {
var y = $(this).scrollTop();
var mTop = y - elpos;
if ((y + el.outerHeight()) < $container.height()) {
if (y < elpos) {
el.stop().animate({
'margin-top': 0
}, 500);
}
else {
el.stop().animate({
'margin-top': y - elpos
}, 500);
}
}
});
not 100% sure what you mean - you want to stop "answers" being pushed lower than "questions"? something like this?
http://jsfiddle.net/X3cbB/1/

How do I constrain the size of a tooltip/popup-style DIV so that it doesn't trigger scrollbars on the page

The mouse hovers over an element and a tip appears. The tip overflows the page, triggering a scrollbar, which changes the layout just enough so that the underlying element that triggered the tip is no longer under the mouse pointer, so the tip goes away.
The tip goes away, so the scrollbar goes away, and now the mouse is again over the element.
Wash, rinse, repeat.
If I could make sure that tip isn't too big so as to trigger scrollbars, that would solve my problem.
EDIT: After reading comments, some things to clarify:
The div contains text which can vary. If I can, I want to show all the text. The div's location needs to be near the element the mouse's tip is over. So the key is, I need to know whether to truncate the text.
I did find this link:
http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
which contains this piece of the puzzle, figuring out how big the browser window is:
function alertSize() {
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
window.alert( 'Width = ' + myWidth );
window.alert( 'Height = ' + myHeight );
}
CSS : specify the tooltip's width and height, add overflow: hidden or overflow: scroll to it.
position: absolute works fine too, but of course, then you'll have to specify the top and left position of the tooltip.
edit: in response to the comments, it sounds like you're trying to have the tooltip appear, without affecting the positioning of existing elements (and thus causing the scrollbar on the main window).
if that's the case, you want to define your tooltip's position as absolute, as this will remove it from the flow of elements (so when it appears it won't push the rest of the page down).
for example, you could start it hidden:
#tooltip {
position: absolute;
height: 100px;
width: 200px;
border: 1px solid #444444;
background-color: #EEEEEE;
display: none;
}
then, on your mouseover event (or whatever it's called on), set the top and left css of the #tooltip to where ever you want it, and switch the display to block. as it's positioned absolutely, it won't cause the flicker.
you can use a hidden DIV positioned at 0,0 with width and height set to 100% as a 'yardstick' to measure the client area of the screen
if you know the size of your tooltip window, you can clip it to the client window, or change the display position to shift it so that it stays within the boundaries
some code below (untested, ripped from another project and renamed inline)
var toolTipDiv; //this is your tooltip div element
//call AdjustToolTipPosition(window.event);
function AdjustToolTipPosition(e)
{
var cpos = getPosition(e);
mouseX = cpos.x;
mouseY = cpos.y;
//Depending on IE/Firefox, find out what
//object to use to find mouse position
toolTipDiv.style.visibility = "visible";
//backdrop 'yardstick' for client area measurement
var backdropDiv = document.getElementById("divBackdrop");
//make sure floating box doesn't leave the screen
//we know box is 200x200 plus margins, say 215x215
if ((cpos.y + 215) > backdropDiv.offsetHeight)
{
cpos.y = backdropDiv.offsetHeight - 215;
}
if ((cpos.x + 215) > backdropDiv.offsetWidth)
{
cpos.x = backdropDiv.offsetWidth - 215;
}
toolTipDiv.style.left = cpos.x + "px";
toolTipDiv.style.top = cpos.y + "px";
}
//this function courtesy of
//http://hartshorne.ca/2006/01/23/javascript_cursor_position/
function getPosition(e)
{
e = e || window.event;
var cursor = {x:0, y:0};
if (e.pageX || e.pageY)
{
cursor.x = e.pageX;
cursor.y = e.pageY;
}
else
{
var de = document.documentElement;
var b = document.body;
cursor.x = e.clientX +
(de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0);
cursor.y = e.clientY +
(de.scrollTop || b.scrollTop) - (de.clientTop || 0);
}
return cursor;
}
Here is the code that I ended up using, and it seems to be working.
function display_popup(s)
{
var popup = document.getElementById("popup");
popup.innerHTML = s
//viewport_height = $(document).height() doesn't work
viewport_height = get_viewport_size()[1] // does this factor in scrollbar?
mytop = $(current_element).offset().top + $(current_element).height() + 4
scroll_offset_y = $(document).scrollTop()
y_in_viewport = mytop - scroll_offset_y
if (y_in_viewport < viewport_height) // are we even visible?
{
// Display the popup, but truncate it if it overflows
// to prevent scrollbar, which shifts element under mouse
// which leads to flicker...
popup.style.height= ""
popup.style.display = "block";
if (y_in_viewport + popup.offsetHeight > viewport_height)
{
overflow = (y_in_viewport + popup.offsetHeight) - viewport_height
newh = popup.offsetHeight - overflow
newh -= 10 // not sure why i need the margin..
if (newh > 0)
{
popup.style.height = newh
}
else
{
popup.style.display = "none";
}
}
popup.style.left = $(current_element).offset().left + 40
popup.style.top = mytop
}
}
function get_viewport_size()
{
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' )
{
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
}
else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) )
{
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
}
else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) )
{
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return [myWidth, myHeight];
}
Seems to me that what you need is cursor position within the client browser window. Then you can do your calculations to place the tooltip so it doesn't cross the border.
What I found on the web is a short article discussing this in diffrent browsers: Mouse Cursor Position. Maybe this could help you fix your problem?
And some more info about browser size can be found here.
Hope it helps.
It could be possible to setup a ghost transparent DIV exactly of you whole page/viewport size. Then you can 'stick' a tooltip DIV within it, providing CSS float:right attribute. That would give you correct top/left tooltip's corner measures for a final tooltip rendering.
Edit: this should be done only for the case of 'edge situations'.
You could try determining where the pointer is, and if it is in the right 1/4 (or whatever area you determine) of the viewport, put the tool tip on the left of the pointer, otherwise put it to the right.
You mentioned that the text can vary, but is it possible it will grow very large? Could it take up an entire screen itself? Most likely, there is a maximum size it will be, so take that into account when deciding what threshold to use to decide if the tip should be on the right or the left.
Then, absolutely position your tip div, and to be safe, give it a max-height and max-width attribute. If the text does grow larger than that, give it overflow: scroll in the CSS.
I had this same problem earlier this year. The way I fixed it:
I assumed vertical scrolling is ok, but horizonal scrolling is not. (There was always enough room so that the vertical scrollbar didn't affect my layout)
I fixed the relative vertical position of the tooltip with regards to the target. (The top of the tooltip was always 5px below the bottom of the anchor)
The left side of the tooltip was set with regard to the size of the screen. If the whole tooltip could fit on one line, cool. Otherwise, I constrained the max width and made it wrap.
One thing that helped me implement it this was was Quirksmode's Find Position article.
My solution might not be exactly what you're looking for, but at least have a look at the Quirksmode link, its good.
Hope that helps!
A better idea may be to place the tooltip to the left or to the right of the element depending on which side of the page is closer. I have width of my tooltip fixed, fill it with content and make it visible when needed, and then position it depending on mouse position. Here's the key part of onmousemove event handler when tooltip is enabled:
if (!e) var e = window.event;
if(e) {
var posx = 0;
var posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
var overflowX = (document.body.clientWidth + document.body.scrollLeft + document.documentElement.scrollLeft) - (posx + 25+ tooltip.clientWidth);
if(overflowX < 0) posx -= 25+ (tooltip.clientWidth);
var overflowY = (document.body.clientHeight + document.body.scrollTop + document.documentElement.scrollTop) - (posy + 15+ tooltip.clientHeight);
if(overflowY < 0) posy += overflowY;
tooltip.style.left=(10+posx);
tooltip.style.top=(10+posy);
}

Categories