I am attempting to build a responsive interface using jQuery UI, that allows for movable and resizable elements, which will stay in proportion even if the screen is resized.
Example: http://jsfiddle.net/NSLmQ/3/
I am using the UI callbacks for dragStop
and resizeStop
to convert the pixel position values into percentage values, after the user has completed their resize or drag.
function resizeStop(event, ui){
convert_to_percentage($(this));
}
function dragStop(event, ui){
convert_to_percentage($(this));
}
function convert_to_percentage(el){
var parent = el.parent();
el.css({
left:parseInt(el.css('left'))/parent.width()*100+"%",
top: parseInt(el.css('top'))/parent.height()*100+"%",
width: el.width()/parent.width()*100+"%",
height: el.height()/parent.height()*100+"%"
});
}
This works perfectly fine if the parent container has an explicit height and width — jQuery UI converts the percentages back to pixels before subsequent resize or drags, and my callbacks return them to percentage after the finished resize or drag. All hunky-dory.
The problem occurs during resize when the resizable element's parent is set to height:auto (in the linked Fiddle, I am using a child image to give the containing parent a height)
When I attempt to resize the UI element, jQuery UI will improperly convert the percentage of the top and left into pixels, and the element will jump in position.
This problem seems to be Chrome-specific. Firefox exhibits occasional mini-jumps in position, but they seem to be a matter of slight rounding differences. In Chrome, the position shifting is dramatic.
While setting an explicit height on the parent container solves the UI problem, it doesn't allow for a responsive solution.
Any ideas?
===========================================
@peteykun's answer below solved my fundamental problem, but there was one offshoot problem that I thought it might be worth addressing.
Chrome uses sub-pixels when calculating 'auto' sizing, so that getting the height with jQuery through .height()
returns an inexact, rounded answer (and causes a visual jiggle during the conversion between pixels and percentage, and vice-versa).
Therefore, using the Vanilla JS .getBoundingClientRect().height
instead of .height()
returns a sub-pixel result for a jiggleless solution.
function setContainerSize(el) {
var parent = $(el.target).parent().parent();
parent.css('height', parent[0].getBoundingClientRect().height+'px');
}
Thanks again for your help, @peteykun
How about setting the container's height
explicitly before the resize takes place?
Ideally, this should have been doable with the start
option for .resizable{}
, but I tried it out myself, and it did not help. Instead, by binding a .mouseover()
to the handle, the desired effect seems to be achieved:
$('.box')
.resizable({containment: 'parent', handles: "se", create: setContainerResizer, stop:resizeStop})
function setContainerResizer(event, ui) {
console.log($(this)[0]);
$($(this)[0]).children('.ui-resizable-handle').mouseover(setContainerSize);
}
function setContainerSize(el) {
var parent = $(el.target).parent().parent();
parent.css('height', parent.height() + "px");
}
JSFiddle: http://jsfiddle.net/w2Jje/4/
Update: In order to retain responsiveness, you can make the height Check the update below.auto
once again after the resize is complete.
function convert_to_percentage(el){
var parent = el.parent();
el.css({
left:parseInt(el.css('left'))/parent.width()*100+"%",
top: parseInt(el.css('top'))/parent.height()*100+"%",
width: el.width()/parent.width()*100+"%",
height: el.height()/parent.height()*100+"%"
});
parent.css('height', 'auto'); // Set it back to auto
}
JSFiddle: http://jsfiddle.net/w2Jje/5/
Update #2: To get around the case where the mouse never leaves the handle before a second resize, let's reset the height on mouseout instead:
function setContainerResizer(event, ui) {
console.log($(this)[0]);
$($(this)[0]).children('.ui-resizable-handle').mouseover(setContainerSize);
$($(this)[0]).children('.ui-resizable-handle').mouseout(resetContainerSize);
}
function resetContainerSize(el) {
parent.css('height', 'auto');
}
JSFiddle: http://jsfiddle.net/w2Jje/6/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With