I am using the C3 JavaScript library for the display of graph data. When my page initially loads, the graphs are hidden. It isn't until a "tab" on the page is selected that the graphs display.
The trouble I am seeing is that my first graph doesn't fit its containing div tag when first loaded. I can change the date range I'm viewing data for by clicking a button, at which time the graphs will be correctly sized.
Here is the relevant HTML that I'm using for the graphs (notice that I am using AngularJS, in case that helps/hinders things at all):
<div class="chartgrouping">
<div ng-show="showGraphSection" class="graphA">
<h2 class="section-main-heading">Data A</h2>
<div id="dataAChart" class="chart c3"></div>
</div>
<div ng-show="showGraphSection" class="graphB">
<h2 class="section-main-heading">Data B</h2>
<div class="stats">
<div class="highest-value">Data Breakdown<span>{{percentageOfSubstance}}%</span></div>
<div class="goals">GOAL: 20%</div>
</div>
<div id="dataBChart" class="c3" style="max-height: 320px; position: relative;"></div>
</div>
</div>
The initial, incorrect display (the first graph stretches the entire way across):
And the correct result after loading new data, after the first result (above) has been displayed:
Is there a good solution to this problem?
I have found the solution relates to how it determine the full width of the element when hidden (often the case when using bootstrap tabs etc and other hidden elements).
To get around this, you need to trigger the resize event on the window to make d3 (the underlying graphing library) work out the correct sizing.
jQuery(window).trigger('resize');
You can do this on bootstrap using something akin to
jQuery('a[data-toggle=tab]').on('shown.bs.tab', function() {
jQuery(window).trigger('resize');
});
In my case, #Flanamacca's answer only partially worked. Loading the chart data with a setTimeout with delay of 0 seems to fix it.
After trying a variety of possibilities, I finally found a solution. It's an Angular solution, so anyone else experiencing the problem and not using Angular will need to modify it appropriately.
How I solved it was, rather than using an ng-show on the parent div, I removed that one and added exact copies of it to each sub-tag (the h2 and the h2s' siblings). Simple solution, but such a pain to figure out.
The jQuery(window).trigger('resize'); stuff didn't work for me.
But using C3 resize ( ) function works like a boss :
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [
['data1', 300, 350, 300, 0, 0, 0],
['data2', 130, 100, 140, 200, 150, 50]
],
types: {
data1: 'area',
data2: 'area-spline'
}
}
});
$('.collapse').on('shown.bs.collapse', function() {//Your event listner
chart.resize();
});
If you are using Foundation with multiple tabs then the following worked for me,
$('#myPanelId' ).on('toggled', function(){
jQuery(window).trigger('resize');
})
Where myPanelId is the panel id which contains the charts.
#Flanamacca's answer didn't work for me, though it was a bootstrap tab-related problem so I did use the jQuery selector they suggested.
What worked for me was the c3 flush() method, which forces the chart to redraw (see http://c3js.org/reference.html#api-flush).
$('a[data-toggle=tab]').on('shown.bs.tab', function() {
my_c3_chart.flush();
});
Simply setting the CSS max-width of the div containing the chart worked for me.
Our situations might be different, but maybe someone with a more comprehensive understanding of how html is rendered can extrapolate from this.
my problem was that I was hiding the graph until my data was pulled in and the graph was generated with c3.generate. I was hiding the graph using css "display: none;". this was what caused the issue. once I changed my css to "opacity: 0," the issue went away.
Related
I'm having slight troubles with the jQuery Waypoint plugin, and any information/help is appreciated.
Ok, so to define what I want to do: I have images, that are hidden prior to being in the view area. I want them to do an animation effect once in the view area. That is the final result, for now, I'm still in testing as I am generally new to jQuery but getting better.
So I started out doing the shake on a single div, and it worked great once the once it was in view. I used the following code:
HTML:
<div class="shown">Shake it</div>
jQuery
jQuery(document).ready(function($){
$(".shown").waypoint(function(direction) {
$(this).effect("shake");
}, { offset: '95%', triggerOnce: true });
});
Then I made two instances of the class='shown' in my HTML (one at top, and one at the bottom), and when I scrolled to them, they both worked great. Plus, they both worked at separate times, which is what I'm trying to gain.
Here's the trouble
When I tried to 'display:none' and then animate to show on scroll, it animates BOTH, instead of just the single at a time.
This is what I'm using
HTML
<div class="shown" style="display: none;">
jQuery
jQuery(document).ready(function($){
$(".shown").waypoint(function(direction) {
$(this).fadeIn( 10000, function() {
// Animation complete
});
}, { offset: '95%', triggerOnce: true });
});
Ok, so just to clarify one more time :D (to be safe)
I want to be able to use the same class for MULTIPLE instances, that will only display once THAT element is in view. Right now it's displaying ALL elements once 1 instance is in view.
Again, any information/help is appreciated. You guys have a great community here, I'm glad I could join!
I am using Google's line chart almost exactly as the demo - only the data has changed - inside of this jQuery tab plugin with no modification. Maybe 50% of the time, the chart will load at 400x200 even though it has been specified to load at 700x250. The containing div will have the proper width and height, but the chart as rendered by the API will load inside of that at 400x200.
I suspect this is because the tabs aren't being displayed when the API tries to render. Because of that, it tries to render in something it considers null and therefore forces itself into the smallest default resolution.
My thought is that if the display of the chart can be delayed until the appropriate tab is clicked, it would resolve the problem. Sadly, I have no idea how to do that, and my research hasn't been fruitful. The closest I could find is this thread, but I didn't find any real answers there.
I'd appreciate any advice if you have any, and I'd be glad to follow up with more information if necessary.
Rendering charts in a hidden div (which is what the non-selected tabs of a tab UI most likely are) messes with the Visualization API's ability to detect dimensions, so you want to do one of two things: either render all charts before instantiating tabs, or (as you've caught on to) bind event listeners to draw the charts when a tab is first opened. Setting the height and width in the chart's options is insufficient to solve the problem in all browsers.
I scanned over the easytabs documentation, and it looks like you should be able to do something like this:
// draw chart(s) in your default open tab
// track which tabs you've drawn charts in
var chartsDrawn = {
tab1: true,
tab2: false,
tab3: false
// etc
};
$('#tab-container').bind('easytabs:after', function (e) {
if (e.tab == 'tab-2' && !chartsDrawn.tab2) {
// draw chart(s) in tab 2
chartsDrawn.tab2 = true;
}
else if (e.tab == 'tab-3' && !chartsDrawn.tab3) {
// draw chart(s) in tab 3
chartsDrawn.tab3 = true;
}
// etc
});
change chart options to set the width and height as you need
var options = {
title: 'Company Performance'
,width:900
,height:500
};
This is how I solved using angular-bootstrap https://angular-ui.github.io/bootstrap/
<div class="google-chart" google-chart chart="chartObject1" on-ready="displayGoogleCharts()"></div>
<tab heading="Past Week" select="googleChartSizeFix()">
googleChartSizeFix = function() {
$('svg').parent().css({ opacity:"0" });
$(window).resize();
};
displayGoogleCharts = function() {
$('svg').parent().css({ opacity:"1" });
};
Each time a Tab is selected (the function googleChartSizeFix is triggered) the Google Chart is set to transparent (opacity = 0, so it does not disappear by the use of hide(), but keeps its size since its content is transparent) followed by the window resize is triggered, this forces Google Chart to fit the div that contains it, by the use of width 100% and height 100%:
"options": {
"chartArea": {
"width":'100%',
"height":'100%'
}
}
and finally once the Google Chart is ready (after resize) the displayGoogleCharts function is triggered and the opacity of the google chart is reset to 1, so the content is visible once again.
I stumbled across this "feature" of Bootstrap tabs. When cut-and-pasting multiple tabs in my HTML, I accidentally left the <div class=" tab-pane active"> in the "active" state for all the tabs. The result was that the content for all the tabs displayed sequentially in the first tab, but went away as you switched tabs.
My solution to the hidden tabs is to define them as active and then remove the "active" class from the div after I call chart.draw.
<div class="tab-pane active" id="myid" role="tabpanel">
<script type="text/javascript">
// all the chart stuff
chart.draw(data, options);
$('#myid').removeClass('active');
</script>
</div>
I see that jQuery tabs also use the "active" class. Perhaps this trick will work there too.
I solved this by, leaving off the bootstrap class in the element holding the chart, and then after chart had been loaded, then apply the bootstrap class.
For example lets say we want to setup a collapsible with the chart in it:
<a href="#div-id" data-toggle="collapse">
Expand
</a>
<div id="div-id" class="future-collapse">
<div id="some-chart"></div>
</div>
And then in your script:
/**
* Callback function E.G. google.charts.setOnLoadCallback(drawChart);
*/
function drawChart(){
// Drawing the charts
draw_some_chart();
// Applying the collapse class to our elements with the future-collapse class
$('.future-collapse').attr('class', 'collapse');
}
function draw_some_chart(){
// Draw your charts
}
I have widgets in my page, where each widget's width cannot exceed more than 400px. Data is completely driven from backend(I do not have any control on it).
The problem is if my tool tip's length is more than certain limit, it hides the data. Please see the screen shot attached to my message on another forum.
Please let me know if there is any solution for this.
You can control where the tooltip displays using positioner like so:
tooltip:
{
positioner: function ()
{
return { x: 80, y: 50 };
}
},
Here is a demonstration. Then you could use the formatter to display the data in the tooltip properly so it does not extend past the width of your contorl.
Can any body help me to find out, how to print dynamic graph as example generated by flot.
I tried this one but it's printing whole page, but I want only graph portion.
function printGraph(){
$('<img src="../images/button_refresh.png" alt="Print Graph" style="">').appendTo(controlholder).click(function (e) {
//Canvas2Image.saveAsPNG(document.getElementById('placeholder'));
//canvas.toDataURL("image/png");
window.print('placeholder');
});
}
This article describes how to copy the canvas to a normal img which can then easily be printed or saved as an image.
The important part:
img.src = canvas.toDataURL();
See the great answer below from Ignacio Correia for more details.
Launch a new window with only the graph or with alternate css similar to what google maps does when you print.
Attention this post have been edited, please see all possible solutions
From what I have searched and found you have only 2 choices or try to print the CANVAS, or EXPORT as an image or my idea is to separate the image from the content and try to print only the graph. Here is a FAQ by Flot, how can you export the image: Question Number 3
Q: Can I export the graph?
A: You can grab the image rendered by the canvas element used by Flot
as a PNG or JPEG (remember to set a background). Note that it won't
include anything not drawn in the canvas (such as the legend). And it
doesn't work with excanvas which uses VML, but you could try
Flashcanvas.
SOLUTION 1 - Export image:
Export image to computer and then print it
SOLUTION 2 - FLOT to CANVAS:
Saving canvas as images - By Mozilla
Save as Image Flot Plugin
Related question - Problem printing in IE8
SOLUTION 3 - My own, Modal printing
This is not the best solution by far but it works, here is a demo:
JSFIDDLE Normal Demo
JSFIDDLE Fullscreen Demo
Steps
Load Fancybox
Open using INLINE FRAME the graph
PRINT on callback after show
Reload the page after print to redesign the page
Here is the necessary code:
$(document).ready(function() {
$(".various").fancybox({
maxWidth : 800,
maxHeight : 600,
fitToView : false,
width : '70%',
height : '70%',
autoSize : false,
closeClick : false,
openEffect : 'none',
closeEffect : 'none',
afterShow : function() {
alert('You are about to print the graph!');
window.print();
},
afterClose : function() {
alert('We need to refresh the page!');
window.location.reload(false);
}
});
});
Extra
This related question is about exporting Flot to PDF, don't know if you may be interested: Export Flot to PDF
EDIT - WORKING SOLUTION
Here is a working demo of how to export the image: FLOT to IMAGE
You could hide the parts of the page you don't wish to print by using a separate stylesheet that has media="print". This would also allow you to tweak the final printed output of the graph itself, for example making it larger.
Found a solution by using html2canvas. First assign the container div to have id like "theChart".
<div class="box" id="theChart">
<div id="placeholder"></div>
</div>
Now we can create an image:
html2canvas($('#theChart')).then(function(canvas) {
image = canvas.toDataURL("image/png");
document.location.href=image;
});
This will also solve the problem when canvas.toDataURL() does not render axis labels.
I want to auto-generate a HTML table from some custom data. One of the columns in my data is a number in the range 0-100, and I'd like to show it in a more graphical way, most desirably a colored horizontal bar. The length of the bar would represent the value, and the color would also change (i.e. below 20 it's red, etc.)
Something like this (created with paint.net):
(source: thegreenplace.net)
One way this can be achieved is by generating an appropriate .PNG and placing it there as an image. But I think that it can probably be done with some concoction of HTML/CSS/Javascript in an automatic way (i.e. the values thrown into the table are numeric, and JS converts them to bars before showing).
Perhaps someone has done something like this already and can share?
Thanks in advance
P.S: If it can work in IE6, that would be best (don't ask...)
P.P.S: It should work offline, so existing webservices (like Google charts) won't help
AListApart has a great article on how to generate charts using purely CSS. It's nice because it is accessible, meaning even without CSS it will provide meaningful data.
http://www.alistapart.com/articles/accessibledatavisualization
Update: According to one of the commenters on this answer, this solution will also work in IE6.
This is doable.
2 options:
1) put an image in every cell using the img tag and resize the image using the width attribute
2) put a div with a pre-set height and change the width according to the value you want it to display. Use the background color of the div as your color - no images needed.
example:
<table style="border: 1px solid black">
<tr><th>name</th><th>value</th></tr>
<tr><td>hi</td><td><div style="height: 10px; width: 35px; background-color: #236611">35</div></td></tr>
<tr><td>yes</td><td><div style="height: 10px; width: 15px; background-color: #236611">15</div></td></tr>
<tr><td>see?</td><td><div style="height: 10px; width: 75px; background-color: #2366aa">75</div></td></tr>
</table>
... you could/should tweak the sizes to look nicer of course :-)
The best way is the second part of simon's post. Place a div wherever you need it and change the width with javascript or PHP (depending on if you want it to dynamically change or not) using percentages. Use an if statement for the color. For ex, in javascript:
function displayGraph(barID, number)
{
var color;
if (number <= 20)
{
color = "red";
}
elseif (number > 20 && number <= 60)
{
color = "yellow";
}
else
{
color = "green";
}
var bar = document.getElementById(barID);
bar.style.width = number + "%";
bar.style.backgroundColor = color;
}
I didn't test this exactly, but something like it should work.
Check out the jQuery Sparkline which provides inline charts, similar to what you are looking for. If you use a bullet graph, you can display the good/normal/bad ranges associated with your data which provides a huge amount of data in a very small space.
Since you already have your data in a table, you might check out the jQuery Visualize Plugin. Once you include it, you'd just call something like:
$('table').visualize();
and it builds a graph from your table.
If you want it to work offline as well, maybe flot can be used.
It is based on canvas and jquery.
I haven't used it yet but it's on my todo list.
The sample code seems simple enough:
$(function () {
var d1 = [[0, 3], [4, 8], [8, 5], [9, 13]];
$.plot($("#placeholder"), [ d1 ]);
});
It's not HTML, but have you looked into Google Charts? It's really quite amazing.
http://code.google.com/apis/chart/