I have a div element which is made jquery Resizable. It has alsoResize option set, so other elements resize simultaneously.
What I want to do, is to set size of this Resizable div element programmatically in such way, that all Resizable logic is triggered (especially this alsoResize option is taken into account).
How can I achieve that?
Update: It looks like the internals of jQuery UI have changed dramatically since I answered this and firing the event no longer works.
There's no direct way to fire the event anymore because the resizable plugin has been fundamentally changed. It resizes as the mouse is dragged rather than syncing items up at the end. This happens by it listening for the internal resize propagation event for resizable plugins which is now fired by the _mouseDrag handler. But it depends on variables set along the way, so just firing that even internally won't help.
This means even overriding it is messy at best. I'd recommend just manually resizing the alsoResize elements directly, independent of the UI widget altogether if that's possible.
But for fun let's say it isn't. The problem is that the internals of the plugin set various properties relating to previous and current mouse position in order to know how much to resize by. We can abuse use that to add a method to the widget, like this:
$.widget("ui.resizable", $.ui.resizable, {
resizeTo: function(newSize) {
var start = new $.Event("mousedown", { pageX: 0, pageY: 0 });
this._mouseStart(start);
this.axis = 'se';
var end = new $.Event("mouseup", {
pageX: newSize.width - this.originalSize.width,
pageY: newSize.height - this.originalSize.height
});
this._mouseDrag(end);
this._mouseStop(end);
}
});
This is just creating the mouse events that the resizable widget is looking for and firing those. If you wanted to do something like resizeBy it'd be an even simpler end since all we care about is the delta:
var end = $.Event("mouseup", { pageX: newSize.width, pageY: newSize.height });
You'd call the $.widget() method after jQuery UI and before creating your .resizable() instances and they'll all have a resizeTo method. That part doesn't change, it's just:
$(".selector").resizable({ alsoResize: ".other-selector" });
Then to resize, you'd call that new resizeTo method like this:
$(".selector").resizable("resizeTo", { height: 100, width: 200 });
This would act as if you instantly dragged it to that size. There are of course a few gotchas here:
The "se" axis is assuming you want resize by the bottom right - I picked this because it's by far the most common scenario, but you could just make it a parameter.
We're hooking into the internal events a bit, but I'm intentionally using as few internal implementation details as possible, so that this is less likely to break in the future.
It could absolutely break in future versions of jQuery UI, I've only tried to minimize the chances of that.
You can play with it in action with a fiddle here and the resizeBy version here.
Original answer:
You can do this:
$(".selector").trigger("resize");
alsoResize internally rigs up a handler to the resize event, so you just need to invoke that :)
You can trigger the bars programmatically. For example, to trigger the east-west resize event:
var elem =... // Your ui-resizable element
var eastbar = elem.find(".ui-resizable-handle.ui-resizable-e").first();
var pageX = eastbar.offset().left;
var pageY = eastbar.offset().top;
(eastbar.trigger("mouseover")
.trigger({ type: "mousedown", which: 1, pageX: pageX, pageY: pageY })
.trigger({ type: "mousemove", which: 1, pageX: pageX - 1, pageY: pageY })
.trigger({ type: "mousemove", which: 1, pageX: pageX, pageY: pageY })
.trigger({ type: "mouseup", which: 1, pageX: pageX, pageY: pageY }));
I am doing a 1px left followed by 1px right movement on the east bar handle.
To perform a full size, you can target .ui-resizable-handle.ui-resizable-se if you have east and south resize bars.
I needed the same thing for tests. Similar questions have only one promising answer https://stackoverflow.com/a/17099382/1235394, but it requires additional setup, so I ended with my own solution.
I have an element with resizable right edge
$nameHeader.resizable({handles: 'e', ... });
and I needed to trigger all callbacks during the test in order to resize all elements properly. The key part of test code:
var $nameHeader = $list.find('.list-header .name'),
$nameCell = $list.find('.list-body .name');
ok($nameHeader.hasClass('ui-resizable'), 'Name header should be resizable');
equal($nameCell.outerWidth(), 300, 'Initial width of Name column');
// retrieve instance of resizable widget
var instance = $nameHeader.data('ui-resizable'),
position = $nameHeader.position(),
width = $nameHeader.outerWidth();
ok(instance, 'Instance of resizable widget should exist');
// mouseover initializes instance.axis to 'e'
instance._handles.trigger('mouseover');
// start dragging, fires `start` callback
instance._mouseStart({pageX: position.left + width, pageY: position.top});
// drag 50px to the right, fires `resize` callback
instance._mouseDrag({pageX: position.left + width + 50, pageY: position.top});
// stop dragging, fires `stop` callback
instance._mouseStop({pageX: position.left + width + 50, pageY: position.top});
// ensure width of linked element is changed after resizing
equal($nameCell.outerWidth(), 350, 'Name column width should change');
Of course this code is brittle and may break when widget implementation changes.
Hack Disclaimer (tested on jQuery 1.12.4):
This basically waits for the dialog to be opened and then increments by 1px (which forces the resize() event) and then decrements by 1px (to regain original size)
just say this in the dialog open event handler:
$(this)
.dialog("option","width",$(this).dialog("option","width")+1)
.dialog("option","width",$(this).dialog("option","width")-1);
note:
This may not work with show effects (like fadeIn,slideDown etc) as the "resizer" code executes before the dialog is fully rendered.
$(".yourWindow").each(function(e) {
$(this).height($(this).find(".yourContent").height());
});
And the same with the width.
Related
I'd like to be able to be able to dynamically toggle the presence of the Highstock navigator and allow the chart to expand into the vertical space it occupied.
I've tried simply toggling chart.userOptions.navigator.enabled but it has no effect.
This thread explains how to use .hide() and .show() methods to conceal the individual components of the navigator and scrollbar, but these use visibility:hidden so the space does not become available for the chart. However, using .css({display: 'none'}) works, but the series itself has no .css() method, and I've been unable to find a way of removing the series from just the navigator.
Does anyone know a method to achieve what I want?
Thanks.
In short: it's not supported to hide navigator in real time. The best way would be to destroy chart and create new one with disabled navigator.
Other solution is to use workaround provided by Sebastian Bochan. Then you will need to update manually yAxis.height, for example: http://jsfiddle.net/dJbZT/91/
$('#btn').toggle(function () {
chart.yAxis[0].defaultHeight = chart.yAxis[0].height;
chart.xAxis[0].defaultHeight = chart.xAxis[0].height;
chart.yAxis[0].update({
height: 500 - chart.plotTop - 35
}, false);
chart.xAxis[0].update({
height: 500 - chart.plotTop - 35
});
chart.scroller.xAxis.labelGroup.hide();
chart.scroller.xAxis.gridGroup.hide();
chart.scroller.series.hide();
chart.scroller.scrollbar.hide();
chart.scroller.scrollbarGroup.hide();
chart.scroller.navigatorGroup.hide();
$.each(chart.scroller.elementsToDestroy, function (i, elem) {
elem.hide();
})
}, function () {
chart.yAxis[0].update({
height: chart.yAxis[0].defaultHeight
}, false);
chart.xAxis[0].update({
height: chart.xAxis[0].defaultHeight
});
chart.scroller.xAxis.labelGroup.show();
chart.scroller.xAxis.gridGroup.show();
chart.scroller.series.show();
chart.scroller.navigatorGroup.show();
chart.scroller.scrollbar.show();
chart.scroller.scrollbarGroup.show();
$.each(chart.scroller.elementsToDestroy, function (i, elem) {
elem.show();
})
});
There's another way to do this: reduce the chart height by the navigator's height, and set chart.reflow to false to prevent the Y-axis from adapting to the new chart height (try setting it to true in the fiddle -- notice the flicker when you show / hide the navigator?).
I've added this answer to the other thread, and the demo is here: http://jsfiddle.net/dJbZT/148/ (credits to Sebastian Bochan for the original answer).
I'm not sure when highcharts added this ability via options, but this worked for me:
var chart = $('#graphContainer').highcharts();
chart.options.navigator.enabled = !chart.options.navigator.enabled;
$('#graphContainer').highcharts(chart.options);
What I want to do is track the (top, left, width, height, zIndex) style attributes. But since the element that holds these styles doesn't exist until after third party code gets pulled in, i can't do it the normal way.
Here's what I've got thus far:
my.Module = function (module) {
return {
top: ko.observable(200);,
left: ko.observable(100);,
width: ko.observable(100);,
height: ko.observable(100);,
zIndex: ko.observable(0);,
};
};
This would be the normal binding context:
<div data-bind="style:{width:width, top:top, left:left, height:height, zindex:zIndex}"></div>
But the third party stuff ends up wrapping the div i pass it within another, and this is something I cannot change. So instead I've started creating a custom bindinghandler:
ko.bindingHandlers.Window = {
init: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
//Do third party creation stuff here...
ko.applyBindingsToNode(elemToActuallyWatch, {
style: {
width: value.width() + 'px',
height: value.height() + 'px',
top: value.top() + 'px',
left: value.left() + 'px',
zIndex: value.zIndex()
}
});
},
Now this applies the above styles to the appropriate div, but i still need the above values to change when both the data changes and when the element changes.
I feel like the 'px' that i have to tack on the ends shouldn't be needed but that was the only way i could get them to apply.
Is there a way from this point on, that lets say I'm using jqueryUI draggable and resizable, and a user moves/resizes the element that the values will automatically update the viewmodel data? Of course a non jquery specific answer would be best.
style is a one-way binding, from model to view. It won't update the model from the view. You'll probably need to use the resize option and update the model from there.
I've installed Datepicker for Bootstrap and its working nicely. But I can't figure out how to use the place method to position the datepicker above the element instead of below. I'm guessing it works similiar to the bootstrap popovers, but I haven't been able to figure it out.
Any suggestions?
The place function just auto places the date picker under your input box. Its not a function that lets you select where you want to place it.
However you can easily override the default functionality of that function with your own custom placement.
Here is an example of that http://jsfiddle.net/G7sWL/19/
All i did copy the original function and add an additional vertical offset of 10 and horizontal offset of 50.
$(function() {
var picker = $('.datepicker').datepicker();
var widget = picker.data('datepicker');
widget.place = function(){ //the original place function
var offset = this.component ? this.component.offset() : this.element.offset();
this.picker.css({
top: offset.top + this.height + 10, // change #1 = added "+10"
left: offset.left +50 // change #2 = added "+50"
});
}
});
From the page:
.datepicker('place')
Updates the date picker's position relative to the element
It only says it updates the position of the picker (which is absolutely positioned on the page), not that you can change its placement.
I am using the jquery-ui draggable component with jquery.gantt here. I could do enable drag on the items easily by $('.ganttRed').draggable() but the problem with this is that once we start scrolling the graph left to right using the slider below, the elements that are moved remain where they are instead of scrolling with the graph.
I looked through the source and from my understanding the margin-left is being changed during the scrolling; but jquery-ui uses the left attribute and in the presence of left the element keeps its position. My CSS knowledge ends just about there so if any of you are willing to provide any suggestions on how this can be fixed; I will greatly appreciate it.
I have a created a fiddle demonstrating the problem at: http://jsfiddle.net/Y2cxa/. In order to see the behavior I am speaking about:
Scroll the graph (either with your mouse wheel or the slider at the bottom); things should look and behave as expected.
Move any of the magenta(-ish) bars around and then scroll.
Again, thank you for your time and any assistance will be greatly appreciated.
Best regards
You have probably solved this or done something else by now but since I needed this aswell i solved it.
Got a solution for you here:
http://jsfiddle.net/Y2cxa/18/
First I simply copied the left value to margin-left and then removed the left value completely, however this led to some strange numbers.
To solve this I compared the start value of left with the final value of left and applied the same difference in pixels to margin-left!
Simply replace:
$('.ganttRed').draggable({axis:'x'});
with:
$('.ganttRed').draggable({
axis:'x',
start: function(event, ui) {
$(this).data("startx",$(this).offset().left);
},
stop: function(event, ui) {
var change = $(this).offset().left - $(this).data("startx");
var value = $(this).css('margin-left');
value = value.split("px");
value = parseInt(value[0]) + change;
$(this).css('margin-left', value);
$(this).css('left', '');
}
});
I believe below is a better solution and I am using it in my application
For vertical and horizonal dragging
$('.ganttRed').draggable(
{
start: function (event, ui) {
$(this).data("startx", $(this).css('left').split("px")[0]);
$(this).data("starty", $(this).css('top').split("px")[0]);
},
stop: function (event, ui) {
var left = parseInt($(this).css('left').split("px")[0]);
var changex = left - parseInt($(this).data("startx"));
var top = parseInt($(this).css('top').split("px")[0]);
top -= top % 24;
$(this).css('top', top);
var changey = top - parseInt($(this).data("starty"));
}
});
changex, changey will be used in calculation while updating in database
For horizontal resizing
$(".ganttRed").resizable({ handles: 'e, w' });
What I have currently is a very simple div that has a flexcroll scroll bar. This simple div contains some draggable itmes inside of it. My goal is to be able to drag one of the items and and move it about without the flexcroll scroll bar moving.
As it stands right now if I were to drag one of the items below the viewable area the simple div will scroll down. I would like to prevent this.
I'm using jQuery UI for the draggable items. I've already tried using the option "scroll:false" but this does not work for flexcroll.
I'm sorry I don't have any example code, I'm currently away from my work computer.
flexcroll: http://www.hesido.com/web.php?page=customscrollbar
I don't know if you have already resolved this problem. This morning, I have the same problem and I found your post. After that, I have googled a lot to find a solution without any lucky. So finally, I decided to do someting myself, I hope my idea will help you.
After read the Programming Guid, I found that in this version (2.0) of flexcroll, we could register a function for onfleXcroll whose description could be found by searching the keyword "Pseudo-event: onfleXcroll". This is to say that the method will be executed after a scroll is done. So here, what I restore the "top" style with the value before you drag an element.
Here are the code
var $assetswrapper; // This variable indicates the contentwrapper of you div.
var $assetsscrollbar; // This variable indicates the vscroller of you div.
window.onfleXcrollRun = function () { // This method will be executed as soon as the div has been rendered with the help of flexcroll
// You could find these two divs by using firebug, because the top value of these two divs will be changed when we scroll the div which use the class .flexcroll.
$assetswrapper = $('#contentwrapper');
$assetsscrollbar = $('#vscrollerbar');
}
var wrapperTopPosition = 0; // This is used to stock the top value of the wrapperContent before dragging.
var scrollbarTopPosition = 0; // This is used to stock the top value of the scrollbar before dragging.
var dragged; // This is a boolean variable which is used for indicating whether the draggable element has been dragged.
var dropped = false; // This is a boolean variable which used to say whether the draggable element has been dropped.
$('.draggable').draggable({ // you could change .draggable with any element.
start: function (event, ui) {
// Your code here.
wrapperTopPosition = $assetswrapper.position().top;
scrollbarTopPosition = $assetsscrollbar.position().top
dragged = true;
},
stop: function (event, ui) {
// Your code here.
dragged = false;
dropped = true;
}
});
$('your drag div')[0].onfleXcroll = function () { // This method will be called each time when a scroll has been done.
if (dragged) {
$assetswrapper.css('top', wrapperTopPosition);
$assetsscrollbar.css('top', scrollbarTopPosition);
} else {
// Code here is used for keeping the top position as before even though you have dragged an element out of this div for a long time.
// You could test the scrollbar without this piece of code, if you drag an element out of the div for a long time, the scrollbar will keep its position,
// but after you dropped this element and try to scroll the div, then the scrollbar will reach the end of the div. To solve this problem,
// I have introduced the method setScrollPos with the old top position plus 72. 72 here is to set the scroll increment for this scroll, I know
// this value is not fit for any size of windows, but I don't know how to get the scroll-increment automatically.
if (dropped) {
dropped = false;
$('your drag div')[0].fleXcroll.setScrollPos(false, Math.abs(wrapperTopPosition) + 72);
$('your drag div')[0].fleXcroll.setScrollPos(false, Math.abs(wrapperTopPosition) + 72);
}
}
};
I hope this could give you a help if you haven't found any solution yet.