Highcharts does not resize charts inside tabs - highcharts

I am using twitter bootstrap with tabs. I have multiple tabs and charts inside each tab. Upon browser resize, charts that are not on the current active tab do not get resized. Infact, it looks kind of funny with a thin bar. The current active tab works fine. Has anyone seen this issue and are there any workarounds ?

Here is a working example:
http://codepen.io/colinsteinmann/pen/BlGfE
Basically the .reflow() function is called on each chart when a tab is clicked. That way the chart gets redrawn based on the new dimensions which are applied to the container when it becomes visible.
This is the most important snippet of code:
// fix dimensions of chart that was in a hidden element
jQuery(document).on( 'shown.bs.tab', 'a[data-toggle="tab"]', function (e) { // on tab selection event
jQuery( ".contains-chart" ).each(function() { // target each element with the .contains-chart class
var chart = jQuery(this).highcharts(); // target the chart itself
chart.reflow() // reflow that chart
});
})

This is my fix for this (using jQuery):
$("[data-highcharts-chart]").each(function () {
var highChart = Highcharts.charts[$(this).data('highchartsChart')];
var highChartCont = $(highChart.container).parent();
highChart.setSize(highChartCont.width(), highChartCont.height());
highChart.hasUserSize = undefined;
});
Call this function whenever the chart gains focus to make sure it is resized properly.

I had a similar issue and I found that the best thing was not to load the chart until the tab was shown. So in the tab shown event I was quickly loading the chart (but only once)

I just solved this issue with the following. Using bootstrap version 3.3.5
I am leaving this here because this link showed up when I googled the issue at the beginning. I hope it helps.
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
$(e.target.hash).highcharts().reflow();
});
HTML
<!-- Nav tabs -->
<ul class="nav nav-pills nav-justified" role="tablist" id="taks-tabs">
<li role="presentation" class="active">Met Standard</li>
<li role="presentation">Commended Performance</li>
<li role="presentation">TAKS-M Met Standard</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="taks_met_std"></div>
<div role="tabpanel" class="tab-pane" id="taks_comm_perf"></div>
<div role="tabpanel" class="tab-pane" id="taks_m_met_std"></div>
</div>

add class="chart" to all highcharts containers inside tabs.
add this jQuery code:
jQuery(document).on( 'shown.bs.tab', 'a[data-toggle="tab"]', function () {
$( '.chart' ).each(function() {
$(this).highcharts().reflow();
});
})

I found the answer after looking for sometime. This was driving me crazy so I want to share it with you all since nothing here worked for me.
Add this to your CSS
.tab-content > .tab-pane,
.pill-content > .pill-pane {
display: block;
height: 0;
overflow-y: hidden;
}
.tab-content > .active,
.pill-content > .active {
height: auto;
}
For more details visit the page I found the solution at
https://jonpolygon.com/bootstrap-tabs-100-percent-width-charts/

i fix this problem with the next code.
$('#yourDivChart').highcharts({
chart: {
type: data.EjeX.Tipo,
//width: width,
//height: height,
options3d: {
enabled: true,
alpha: 15,
beta: 15,
viewDistance: 25,
depth: 40
},
width: $('#DivContainerWithYourTabs').width() - 150
},
in my case is a partial "_partialDetalleProyecto"
I hope works you.

So this is a bit old, but for anyone stumbling across this, I was having a similar issue with the highchart sizes being incorrect in a bootstrap tabbed display. The solution I came up with was to just delay creating the chart by 100ms using setTimeout().
setTimeout(function() {
drawBarChart();
}, 100);
Note: drawBarChart is a custom function I created to generate the charts I needed. The issue (at least in my case) seemed to be that the chart was being created before (or at the same time) as the container and was therefore choosing some default width instead of the width of the container.

I have 2 tabs , met same problem.
I changed only 2 rows codes of Druska, and it worked.
function anyname() {
$("[data-highcharts-chart]").each(function () {
var highChart = Highcharts.charts[$(this).data('highchartsChart')];
var highChartCont = $(highChart.container).parent();
highChart.reflow();
});
}
and add one onclick event to you HTML tab codes like below:
<input type="radio" id="tab1_1" checked onclick="anyname();" >

Related

How can I dynamically resize a select2 input to be the same width as the selected option?

I'm building a 'natural language' search form using a series of inline select inputs, using jQuery Select2 for styling. The widths of the Select2 inputs appear to be set to the width of the selected option on initialisation, which is great. I just can't work out how to get the width to update when the selected option is changed. Any ideas?
Many thanks!
Try to add this to yor CSS file:
.select2-container {
width: 100% !important;
}
It solved my resize problems with select2
(Edited: I do not use placeholders)
You can use window resize function.
Example:
// Fix select2 width
$(window).on('resize', function() {
$('.form-group').each(function() {
var formGroup = $(this),
formgroupWidth = formGroup.outerWidth();
formGroup.find('.select2-container').css('width', formgroupWidth);
});
});
I know this is an old post However, I had an issue when I used NMC's code.
As I can't comment on his answer, after using his code I had some annoying scrollbars appearing after using the select2 dropdowns, to fix this I used width auto instead.
.select2-container {
width: auto !important;
}
Just had to do something like this for a site
$(e).on("select2:closing", function(e) {
if (e.hasOwnProperty('params') &&
e.params.hasOwnProperty('args') &&
e.params.args.hasOwnProperty('originalEvent') &&
e.params.args.originalEvent.hasOwnProperty('target')) {
var newWidth = $(e.params.args.originalEvent.target).width();
var id = $(e.params.args.originalEvent.target).attr('id');
var container = $("span[aria-labelledby=\""+id.split("-result")[0]+"-container"+"\"]");
$(container).parents('span.select2').width(newWidth + 21);
}
});
This is probably not fool-proof and is tied to the current API. But it gets the width of the element in the dropdown before the dropdown closes and then applies that to the container.
One thing of note, you may need to float the dropdown items to get their real size.
.select2-results__option {
float: left;
clear: both;
}
$('.select2-search__field').attr('style','width:auto');
$('.select2-search__field[placeholder=""]').attr('style','width:10px');
For dynamically resize a select2 you can use width: 'style' option as below:
$('#field_'+field.name).select2({
placeholder: "select a option...",
maximumSelectionLength: 1000 ,
allowClear: true,
...
width: 'style',
data: data
});
And next you have to use style="width:100%;" as attribute for your select tag.
<select class="input-element-item fontsize13" id="select2" style="width:100%;" >
<option></option>
</select>
For other than problems of responsive width, read the documentation of Select2. Everything is explained.
https://select2.org/appearance#container-width
<select class="js-example-responsive" style="width: 50%"></select>
$(".js-example-responsive").select2({
width: 'resolve' // need to override the changed default
});

jQuery animate() on Chrome 37.0.2062.120 m / Webkit?

This is my first question here on SO, so bear with me. I am developing a small project and I recently discovered one particular problem that I did not have before.
In my project I have a small map used for selection of different regions of my country, Romania. I implemented this with Raphael.js library and jQuery/UI. It looks like this:
http://s28.postimg.org/pzg3gaiod/output_Cuap_Ye.gif
The idea is when you select a region it gets dynamically coloured and added to a vector of regions. Simple. So for every region (that is declared as a path for the Raphael library to understand and paint) I have a small function:
function clickableMinimapRegions(st, regio) {
st[0].style.cursor = "pointer";
st[0].onclick = function () {
if ($.inArray(regio, regions) != -1) {
regions.splice($.inArray(regio, regions), 1);
st.animate({
fill: "#FFFFFF"
}, 0);
} else {
regions.push(regio);
st.animate({
fill: "#e6e6e6"
}, 0);
}
};
}
Then I have this HTML:
<ul class="element-menu drop-up">
<li>
<a id="toggle" class="dropdown-toggle bg-lime text-shadow button shadow">
<img src="../img/regions.png">
</a>
<div id="content" class="dropdown-menu bg-steel" data-role="dropdown">
<div id="minimap" class="minimap"></div>
</div>
</li>
</ul>
I use Metro UI CSS library, it's a simple drop-down menu. But it's behaviour is to autoclose on click. So for that I did:
$("#minimap").click(function (event) {
event.stopPropagation();
});
http://s28.postimg.org/trltqsu19/Captura3.png
This menu is at the bottom of the screen over a leaflet map, the map is the background and this drop-down is over the map. The thing is, if the map is not loaded, than it works fine. If the map tiles are loaded, something is happening that prevents the regions to be coloured when clicked.
Thank you.
SOLUTION FOUND:
Force DOM redraw/refresh on Chrome/Mac
The second parameter in jQuery's .animate() is the duration, in milliseconds. Having set it to 0, I'd rather say the behaviour you see in other browsers is wrong, and you should expect to have the property changed immediately with no animation.
st.animate({
fill: "#FFFFFF"
}, 0);
// ^---- duration
Try changing that to a bigger value (400 ms is the default)
Here's a fiddle showing the difference: http://jsfiddle.net/exrj973b/

iframe prevents iScroll scrolling on mobile Safari

I am using iScroll on my mobile enable website (using iPhone here) to scroll inside a div.
In this this div, I have an iframe with a fixed height like this:
<body>
<div id="iscroller">
<iframe id="theIframe"></iframe>
Other stuff
</div>
</body>
Now, while scrolling within the div, everything works as expected but I cannot scroll when the scrolling gesture begins on the iframe.
The problem is described here pretty well: https://github.com/cubiq/iscroll/issues/41
So, I used the css workaround from that post by applying pointer-events:none to the iframe.
Now scrolling works perfectly but I cannot click any links which are defined within the iframe because all click/touch events on the iframe seems to be blocked due to pointer-events: none.
So, I thought:
"Ok, while the user scrolls, I need pointer-events:none. If he is
not scrolling (and instead clicking), I must set pointer-events:auto
in order to let the click/touch events pass."
So I did this:
CSS
#theIframe{pointer-events:none}
JavaScript
$("#theIframe").bind("touchstart", function(){
// Enable click before click is triggered
$(this).css("pointer-events", "auto");
});
$("#theIframe").bind("touchmove", function(){
// Disable click/touch events while scrolling
$(this).css("pointer-events", "none");
});
Even adding this doesn't work:
$("#theIframe").bind("touchend", function(){
// Re-enable click/touch events after releasing
$(this).css("pointer-events", "auto");
});
No matter what I do: Either scrolling doesn't work or clicking the link inside the iframe doesn't work.
Doesn't work. Any ideas?
I found the perfect solution. Works great on iOS and Android.
The basic idea is to put a div layer on top of that iframe. This way scrolling works smoothly.
If the user wants to tap/click on an element on that iframe I simply catch that click on the layer, save the x and y coordinates and trigger a click event on the iframe's content at these coordinates:
HTML:
<div id="wrapper">
<div id="layer"></div>
<iframe id="theIframe"></iframe>
</div>
Other stuff
CSS:
#layer{
position:absolute;
opacity:0;
width:100%;
height:100%;
top:0;
left:0;
right:0;
bottom:0;
z-index:2
}
JavaScript:
$('#layer').click(function(event){
var iframe = $('#theIframe').get(0);
var iframeDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
// Find click position (coordinates)
var x = event.offsetX;
var y = event.offsetY;
// Trigger click inside iframe
var link = iframeDoc.elementFromPoint(x, y);
var newEvent = iframeDoc.createEvent('HTMLEvents');
newEvent.initEvent('click', true, true);
link.dispatchEvent(newEvent);
});
I found a solution for this, it happens to be close to what other guys already mentioned on github but this may be useful for whoever wants to find a fast working resolution for this problem.
I'm assuming a few things, like there's only one iscroll container, here represented as ID. This is not properly tested and needs refactor. It's working in my project, but I changed it here slightly for the example but I guess you'll easily understand what you need to do:
var $iscroll = $('#iscroll');
document.addEventListener('touchstart', function(e) {
if ($iscroll.find('iframe').length > 0){
$.each($iscroll.find('iframe'), function(k,v){
var $parent = $(v).parent().first();
if ($parent.find('.preventTouch').length == 0){
$('<div class="preventTouch" style="position:absolute; z-index:2; width:100%; height:100%;"></div>')
.prependTo($parent);
};
$parent
.css('position', 'relative').css('z-index', 1);
});
$iscroll.find('.preventTouch').on('click', function(e){
e.preventDefault();
e.stopPropagation();
return false;
});
};
};
document.addEventListener('touchend', function(e) {
if ($iscroll.find('iframe').length > 0){
setTimeout(function(){
var $iscroll = $('#iscroll');
$iscroll.find('.preventTouch').remove();
$iscroll.find('iframe').css('z-index', '');
$iscroll.find('.preventTouch').off('click');
}, 400);
};
};
Thanks for looking!

jquery accordion jump and open to a specific section

i use jquery + jquerui in modx and the accordion. I wan't to have a horizontal menu on the top where I can jump (scroll) to the section (which opens). How would I achieve this.
Right now my js looks like this:
/ Accordion
$("#accordion").children("div").each( function() {
var a = $(this).find("a");
var ref = $(a).attr("href");
$(a).attr("href", "#");
$(this).find("div").load(ref);
});
$("#accordion").ajaxStop(function() {
$(this).accordion({
header: "h2",
active: true,
collapsible: true,
clearStyle: true,
navigation: true
});
});
EDIT: my accordion gets build with wayfinder:
[[Wayfinder? &startId=`6` &outerTpl=`outerTpl` &rowTpl=`rowTpl`]]
rowTpl:
<div>
<h2>[[+wf.title]]</h2>
<div>
<!-- placeholder for content -->
</div>
</div>
outerTpl:
<div id="accordion">[[+wf.wrapper]]</div>
The topmenu (horizontal) gets called like this:
[[Wayfinder? &startId=`6` &outerTpl=`QouterTpl` &rowTpl=`QrowTpl`]]
QrowTpl:
<li[[+wf.id]][[+wf.classes]]><a href="[[+wf.link]]" title="[[+wf.title]]" [[+wf.attributes]]>[[+wf.linktext]]</a>[[+wf.wrapper]]</li>
QouterTpl
<ul class="arrowunderline">[[+wf.wrapper]]</ul>
Thanks for help
You can use the activate method to programmatically open an accordion panel.
See this fiddle for an example.
NB. activate method is deprecated since jquery ui 1.9 and removed since 1.10. More info and alternative can be found here.
use this on .ready function
$("#accordion").accordion('option', 'active' , 3);
3 = the number of specific section in menu you want it active

Get scroll position of panel using SplitView (JQuery Mobile)

I have implemented a WebApp using SplitView - http://asyraf9.github.com/jquery-mobile/ - (and that seems to use the ScrollView component) together with jQuery Mobile. Everything works fine ...
Within the panel I have got a list of elements that should dynamically add elements when scrolling reaches the end of the list. On the iPhone I do not use SplitView but iScroll - http://cubiq.org/iscroll - and the following code to achieve this (and it is working).
HTML:
<div data-role="panel" data-id="menu" data-hash="crumbs" style="z-index: 10000;" id="Panel">
<div data-role="page" id="Root" class="Login" onscroll="console.log('onscroll');">
<div data-role="content" data-theme="d" onscroll="console.log('onscroll');">
<div class="sub">
<ul data-role="listview" data-theme="d" data-dividertheme="a" class="picListview" id="PortfolioList">
<!-- Content added dynamically -->
</ul>
</div>
</div>
</div>
</div>
Javascript:
var defaultIScrollOptions = {
useTransition: true,
onScrollStart: function() {
this.refresh();
},
onScrollEnd: function() {
if (this.elem && this.id) {
possiblyDisplayNextDocuments(this.y, this.elem, this.id);
}
}
};
iScrolls.push(new iScroll(document.getElementById("searchResults").parentNode, defaultIScrollOptions));
But when using SplitView I do not really know which event and which element to bind the listener on or how to get the scroll position. I already tried several combinations, but did not achieve good results. The best one was the following:
$("#PortfolioList").scrollstop(function(event) {
console.log("scrollstop: "+$("#PortfolioList").scrollTop());
});
My question is: Am I using the right event listener (since it already fires althgough the scrolling animation is still in use) and how do I get the scroll position?
dont use the scrollview plugin. its buggy. Use iscroll for both iOS phonegap apps as well as android. It works fine on both.
For detecting the scroll and loading new elements into the list, listen to the the 'onScrollMove' event of iscroll.
In the iscroll-wrapper.js add this-
options.onScrollMove = function(){
that.triggerHandler('onScrollMove', [this]);
};
then in your code attach a event handler to the onScrollMove event and handle adding new rows in that. onScrollMove will fire whenever you scroll.
In the handler you can find how many rows are there in your list and that which row is on the top of your view port using something like
iscrollScrollEventHandler:function(event){
var contentDiv= $('div:jqmData(id="main") .ui-page-active div[data-role*="content"] ul li' );
var totalItemsonList = contentDiv.length;
var cont =$('div:jqmData(id="main") .ui-page-active div:jqmData(role="content")');
var itemToScrollOn = totalItemsonList - x; // x is the item no. from the top u want to scroll on. u need to keep updating i guess
var docViewBottom = $(cont).scrollTop() + $(cont).height();
var itemOffset = $(contentDiv[itemToScrollOn]).offset();
if(itemOffset){
var elemTop = itemOffset.top;
if (elemTop <= docViewBottom){
event.data.callback();
}
}
}
and in the callback add the code to add new rows. hope that helps.

Resources