nvd3 chart error when display:none - d3.js

I am currently using nvd3 for charting in my application. I have a problem in that if the div is hidden via display:none before the charts are rendered, the charts will throw an error, and upon "un-hiding" the div, I have to click on the charts to get them to render correctly. Is there any way to pre-render the charts even if the div is hidden? I have tried setting the width and height of the parent svg before calling the chart, but to no avail.
nv.addGraph(function () {
//chart setup code
d3.select("#chart svg").attr("width", 300).attr("height", 500);
d3.select("#chart svg").datum(data).transition().duration(500).call(chart);
nv.utils.windowResize(chart.update);
return chart;
});

I figured out how to make a previously hidden chart render properly without needing to statically define the dimensions of the chart area:
NVD3 Charts not rendering correctly in hidden tab
This solution also depends on using JS to display the hidden content and at the same time trigger a resize event which forces NVD3 to resize the now visible chart to fill parent. In my case I didn't care about SEO so I used display:none; but visibility:hidden; would work too.

Just add this JavaScript:
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
window.dispatchEvent(new Event('resize'));
})
hidden.bs.tab is the event that fires after a new tab is shown as per the Bootstrap docs. This code fires a resize event after each tab change.

You can hide a chart – but still render the graph – using a class like this:
.out-of-sight-and-space{
visibility: hidden !important;
position: absolute !important;
top: 0 !important;
}
You should apply this to the parent of the svg, in your case #chart. When you want to show the chart, remove the class.

Related

Is it possible to have a scrolling div that adjusts to the number of bars in a dc.js rowchart

I have several rowcharts that are connected to each other with dc.js.
These rowcharts have the x axis at the top in a different div, as explained here. However these rowcharts also implement filtering and removing, therefore, whenever I filter in one rowchart, the number of bars in the others reduce, but it maintains the size of the scrollable div, even though there are no bars below what is shown. Also, I'm pretty sure it is easy, but I haven't figured out how to put the reset button below the chart, because it shows between the chart div and the axis div, as seen below.
Is there a way to correct these issues?
This is what I have in each rowchart div:
<div id='axis'></div>
<div id="chart" style="overflow-y:auto; height:200px;">
<div>
<span class="reset" style="display: none;">Phylum seleccionado(s):
<span class="filter"></span>
<a class="reset" href="javascript:Chart.filterAll();dc.redrawAll();" style="display">Reset</a>
</span>
</div>
</div>
And this is what a I have in each rowchart in the main.js:
Chart
.fixedBarHeight(20)
.height(nonEmpty.all().length * 20 + 1)
.margins({top: 0, right: 20, bottom: 0, left: 20})
.width(600)
.xAxis(d3.axisTop())
.elasticX(true)
.ordinalColors(['#e41a1c'])
.gap(1)
.dimension(Dim)
.group(nonEmpty) //this removes the ones that don't match the filter of the other rowchart
.on('pretransition', function () {
Chart.select('g.axis').attr('transform', 'translate(0,0)');
Chart.selectAll('line.grid-line').attr('y2', Chart.effectiveHeight());
});
Partial answer here. Well, it answers what you asked but doesn't answer the next question I expect. :(
You are currently sizing the chart based on the number of bars, and you will need to resize the chart when the number of bars change.
This should be done in a preRedraw handler, but unfortunately preRedraw is currently fired after resizing is done. So currently you have to override .redraw():
dc.override(chart, 'redraw', function() {
chart.height(chart.group().all().length * 21);
return chart._redraw();
})
As for putting the info & controls after the chart, there are two issues and I was only able to solve one of them.
dc.js will append an svg element to the chart div. It'd be nice to have more control over this but I'm not sure what to do. For the moment, the easiest workaround is to re-append the info div:
chart.on('postRender', function() {
chart.root().node().appendChild(chart.select('div.info').node())
})
However, what you really want is probably to pull the info div out of the scrolling div, and I can't figure that out at the moment. The problem is that the chart expects the controls/info to be inside the chart div, and that's the same one that needs to scroll.
I tried to mess around with adding another scrolling div inside the chart div, and then moving the svg under it. This works, but it creates some annoying flashing.
Here's what I got so far. I may return to this later if I think of a better solution.
Update: controls outside of the scroller
To solve this right, we need the controls outside of the chart div.
We can port baseMixin.turnOnControls to a filtered event handler, and do the same showing and populating that the chart would do:
function turnOnControls(_chart, controls) {
var attribute = _chart.controlsUseVisibility() ? 'visibility' : 'display';
controls.selectAll('.reset').style(attribute, null);
controls.selectAll('.filter').text(dc.printers.filters(_chart.filters())).style(attribute, null);
}
function turnOffControls(_chart, controls) {
var attribute = _chart.controlsUseVisibility() ? 'visibility' : 'display';
var value = _chart.controlsUseVisibility() ? 'hidden' : 'none';
controls.selectAll('.reset').style(attribute, value);
controls.selectAll('.filter').style(attribute, value).text(_chart.filter());
}
function filter_function(controls) {
return chart => {
chart.hasFilter() ?
turnOnControls(chart, controls) :
turnOffControls(chart, controls);
}
}
chart.on('filtered', filter_function(d3.select('#info')));
Also, controlsUseVisibility and visibility: hidden is better when the controls will affect layout when shown/hidden.
(fiddle)

Showing DC bar chart only after on renderlet function is called, and not on render.

I am modifying the bar size and position using attr.
However the chart attributes are only available after the chart gets rendered.
So I am doing the modification on the fuction
chart.on("renderlet.somename", function (chart) {// modification });
My problem is this looks odd, as the chart gets rendered first then the modifications are applied and it all appears on the page.
I want that the chart should only be visible after the modifications has been applied.
I started to write that you could use the pretransition event, since this fires after everything has been rendered/redrawn, before transitions start.
But you are correct that the bar width is not publicly accessible (it should be!) and you can't read it from the bars until they have transitioned.
So, as you suggested, you could instead hide the whole chart using CSS:
<div id="test" style="visibility: hidden"></div>
And then show it at the start of your renderlet:
chart.on('renderlet', function(chart) {
d3.select('div#test').style('visibility', 'visible');
To eliminate the pause, you could also disable transitions for this chart when you initialize it;
chart
.transitionDuration(0)
And re-enable them in your renderlet:
chart
.on('renderlet', function(chart) {
d3.select('div#test').style('visibility', 'visible');
chart.transitionDuration(750); // default value
Here's a demo, using a fiddle demonstrating error bars (which also need the bar width): http://jsfiddle.net/gordonwoodhull/cw86goxy/32/

Kendo UI chart not resizing?

I have a Kendo ui chart which displays a column chart from a dynamic data source. But occassionally, the chart opens half the size of the available space. When I click on some links or change the date, it resizes itself. Any idea why its causing it?
In the datasource change event, its showing the container div's width as 0 when it shows this behaviour. I can give more details if needed
I tried the refresh method as given in one of the answers but its not of help
This happens generally when you open a chart in a animated window before it is finished expanding.
My suggestion is to redraw the chart when you are sure everything is loaded and fully opened.
$("#myChart").data("kendoChart").redraw();
If you have not disabled animations you may want to do that before this and re-enable them after.
$("#myChart").data("kendoChart").options.transitions = false;
When you have got all the necessary data in the controller you can call a Javascript CallBack function in which you can set the transition to false and then redraw the chart and set transition to true, also you can hide the chart by default and make it visible on Javascript CallBack function
Try this
var chart=$("#chart").data("kendoChart");
//to check the chart exist or not if exist then redraw it..
if(chart)
{
chart.redraw();
}
Thanks
This is what I using for my charts:
if($("#areaChart").data("kendoChart")) {
$("#areaChart svg").width(Number($('.k-content').width()));
$("#areaChart svg").height(Number($('.k-content').height()));
$("#areaChart").data("kendoChart").refresh();
}
Taken from here
Have you checked the resize() Method?
I fixed it by adding a small delay after calling the CreateChart() function as below:
CreateChart(this.id, this.id + " this week", "week", null);
sleep(1000);
its working fine now
$("#divSensingData").kendoChart({
chartArea: {
width: 900,
height: 500
},
i did face same problem after resize kendo chart.
$(window).resize(function () { $("#chart").data("kendoChart").refresh(); });
it's working

Text ellipsis applied to jQPLOT AXIS TICKS

My jqplot graphs have, sometimes, long texts as tick text.
I'd like to ask if is any way to short that text (using jqplot) and to add a tool tip with full text on the tick label?
I hope this will help someone looking for the same solution, Originally answered by me here.
The hover is not detecting because of the z-index of the canvas which lies on top of the whole chart. I did the following and now it's shorten the tootip by CSS ellipsis and show the tooltip with full name on hover.
Based on the Gyandeep's answer, the exact JS and CSS I used are,
Javascript:
$('div.jqplot-xaxis-tick').each(function (i, obj) {
$(this).prop('title', ($(this).text()));
$(this).css('z-index', 999); // this is important otherwise mouseover won't trigger.
});
CSS:
.jqplot-xaxis .jqplot-xaxis-tick {
position: absolute;
white-space: pre;
max-width: 92px; // Change it according to your need
overflow: hidden;
text-overflow: ellipsis;
}
The JavaScript part needs to be executed after every rendering of chart. It's better to put them right after plotting the chart and may in the AJAX success handler.

Using a CSS image sprite for hover effect without the scrolling animation

I'm using a sprite image to change the background on hover and click (the .keepImage class is for the click). It all works, but when the background picture changes it scrolls over to the correct position. Is there a way to do it without the scrolling motion?
JS:
<script>
$(document).ready(function(){
$("a.doing").click(function() {
$(this).siblings(".keepImage").removeClass("keepImage");
$(this).addClass("keepImage");
});
});
</script>
CSS:
a.doing {
width: 229px;
height: 202px;
margin-right: 8px;
background: url(http://localhost:8000/img/manifesto/spr_doing.png) 0 0;
}
a.doing:hover, a.doing.keepImage {
background: url(http://localhost:8000/img/manifesto/spr_doing.png) -229px 0;
}
I think, somewhere in your css you have the transition property specified. Usually when you have a transition property specified like this: "transition: all 500ms ease;", the background position will change with a scrolling effect. If you want to prevent this scrolling from happening, then you can either remove the transition property completely, or you can use transition only for the properties you want to animate like - border, color etc.. but not background. If you can somehow provide a link to your page, or give the html mark up and css, it will help. Thanks.

Resources