NVD3.js piechart use in Leaflet control - javascript

I am trying to add some data visualization to web map I am working on and I am exploring the use of D3, specifically NVD3. I am using the PieChart Example as a test run for a proof of concept.
I add a leaflet control to my map like this (forgive the bad formatting):
var visualizationControl = L.control({ position: 'bottomleft' });
var visualizationDiv = L.DomUtil.get("visualizationContainerDiv");
// ...
visualizationControl.onAdd = function (map) {
this._div = L.DomUtil.create('div', 'control');
this._div.innerHTML = result;
return this._div;
}
visualizationControl.addTo(MapProvider.map);
nv.addGraph(function () {
var chart = nv.models.pieChart()
.x(function (d) { return d.label })
.y(function (d) { return d.value })
.showLabels(false);
d3.select("#chart svg") //div with chart Id and svg container within that div
.datum(exampleData())
.transition().duration(350)
.call(chart);
return chart;
});
The chart will render ok in my control, and the on hover behaviour does register correctly.
However, when it appends the tooltip to the DOM it appends it to the body instead of my SVG or even the control div.
It's difficult to tell from this image but this was taken during an on.hover over one of the slices of the pie and it should write out the tooltip on top of the pie slice. Notice the "One 29.77" sitting off to the side in the navbar.
I have been poking around the development version of the NVD3 js and found a few blocks that refer to the tooltip container and it looks like it should append it to the SVG container.
I also tried changing the css of the tooltip to no avail.
I don't want to give up on this just yet. Any suggestions, help, ideas would be greatly appreciated. Thanks.
Using the current versions of leaflet, D3 and NVD3, debugging/testing in Chrome.
UPDATE
I did not solve this problem using NVD3 I did, however, end up using C3js. It also has a pie chart and this played nicely with my L.control(). A word of caution though, (if you try to go with C3) look carefully at how the charts are looking to receive the data that is being passed to them. I had to play with this for while to get them to work.

Related

Double clicking on c3js line chart

I'm trying to create a double-click event on a c3js line chart. I've created double-click events with other kinds of charts with the following code:
chart.internal.main.selectAll('.' + c3.chart.internal.fn.CLASS.eventRect).on('dblclick', function (d) {
var $$ = chart.internal;
$$.main.selectAll('.' + c3.chart.internal.fn.CLASS.bar).each(function (d) {
if ($$.isWithinShape(this, d)) {
...
}
});
But when I try this on a line chart (changing c3.chart.internal.fn.CLASS.bar to c3.chart.internal.fn.CLASS.line) it catches all the lines in the chart, and gives no information on where on the X-axis I'm clicking. I looked through all the other values under CLASS but can't find anything that might correspond to the dots that separate the line segments.
I figured it out. I need to use c3.chart.internal.fn.CLASS.circle. That will tell me which datapoint is being clicked on.
I haven't tried this with circles turned off. It might not work then.

Vertical line in D3 plot move on zoom/pan

I am trying to draw a vertical line marker in my graph in D3. It is modeled off of this example: https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172
My issue is that after I draw my line, it doesn't move as I zoom/scroll the graph. An example is shown below:
Currently, I have it calculated as a d3.area().
this.pastDateArea = d3.area()
.x(function(d) { return this.x(this.props.pastDate.toDate()) }.bind(this))
.y0(0)
.y1(function(d) { return this.height }.bind(this))
It is appended as
var pastDateData = [{x:this.props.pastDate.toDate(), y:150}]
this.focus.append("path")
.datum(pastDateData)
.attr("class", "area")
.attr("d", this.pastDateArea)
and zoomed/brushed using
//zoom
var t = d3.event.transform;
this.x.domain(t.rescaleX(this.x2).domain());
//brush
this.svg.select(".zoom").call(this.zoom.transform, d3.zoomIdentity
.scale(this.width / (s[1] - s[0]))
.translate(-s[0], 0));
I know there are similar questions to this one (namely, Draw a vertical line representing the current date in d3 gantt chart) but none of them include the zooming/panning features I have in my graph.
Please let me know if you need more information and thanks!
The issue is that you are not updating the vertical bar with each zoom event. Using the code of the example you show, several things are done when the chart is zoomed, including as you note:
x.domain(t.rescaleX(x2).domain()); // update x scale
focus.select(".area").attr("d", area); // redraw chart area
While you do give the new area the class of area, d3.select will only pick the first matching element. So, on zoom, only one .area element is updated (the first encountered, generally the first appended). But, replacing this with d3.selectAll(".area") will not generate the intended results as the area function referenced (.attr("d",area) ) is only used for the first area (that of the graph, not of the vertical bar).
A solution is to select each area (the chart and the bar) independently and update the area with their respective area generators. To do so, append the vertical bar with a unique class name, or an id and use that to select it later. Then when updating the graph on zoom or brush you can use:
x.domain(s.map(x2.invert, x2)); // update x scale
focus.select(".area").attr("d", area); // redraw chart area
focus.select(".bar").attr("d", pastDateArea);// redraw vertical bar
Remember that this needs to be done for both zoom and brush. Also, in the given example, a clip path is assigned in the css for .area, so you need to keep that in mind as well.
Here's a modified example.

Nvd3 - scatter chart won't load despite adding all external resources

Please have a look at this JSFIDDLE. I'm trying to follow a tutorial to create a very basic scatter chart in NVD3.js, but to no avail.
function createBasicChart1(){
var chart;
nv.addGraph(function(){
//Create chart
chart = nv.models.scatterChart()
.showLegend(false) // Remove legend (will put it back later)
.showDistX(true) // Show X axis
.showDistY(true) // Show Y axis
.useVoronoi(false) // For now, disable hovering on points
.color(d3.scale.category10().range()) // Colormap
.duration(500); // Fade in duration
// Generate toy data
data = [{key: "", values:[{x:0,y:0},{x:1,y:1}, {x:3, y:3}, {x:3, y:10}]}];
//Add chart to page
d3.select("#basicChart1").datum(data).call(chart)
// Register chart with window resize event
nv.utils.windowResize(chart.update);
return chart
});
}
Could you please tell what I'm missing here? I've added all the resources like the tutorial says.
There is one mistake from you and one mistake from the tutorial's author.
Your mistake is that the ID of the SVG is basicChart1, not basicChart. Actually, it is on the tutorial:
When you write the javascript code, make sure to change the d3 selector id to a one that will match with the template.
The author's mistake is a little bit more strange: in his tutorial, the author never calls createBasicChart1. But, of course, unless it is an IIFE, you have to call it:
createBasicChart1()
Here is your updated fiddle: https://jsfiddle.net/5eydu463/

responsive d3 area graph stretches circle interaction points

I have been experimenting with a simple d3 google analytics-style area graph demo. I'd like to make it stretch to the full width of its container, which I have managed to do. However the little circles are of course stretching out of shape too. I'd like their positions to be responsive, but not their dimensions (so they remain circular).
Fiddle link: http://jsfiddle.net/46PfK/2/
I'm trying to use the SVGPanUnscale.js script. I have tried calling it with unscaleEach('.dot'); and [].forEach.call($('.dot'),unscale); but neither appear to do anything.
This example is responsive in a similar way to mine and uses the script to 'unscale' the axis labels: http://meloncholy.com/static/demos/responsive-svg-graph-1/
This example also uses circle elements:
http://phrogz.net/svg/scale-independent-elements.svg
I looked at solutions involving the css attribute:
circle {
vector-effect: non-scaling-stroke;
}
which created a circular stroke on an ellipse - weird.
A CSS solution would be preferable to a JS one, provided it works across browsers.
Any suggestions?
Thanks to #leMoisela for pointing me in the right direction. I fixed my issue nicely using JS to redraw the graph on resize:
http://jsfiddle.net/46PfK/4/
window.onresize = function(e){
draw_graph();
};
There's a good example on resizing with D3 https://blog.safaribooksonline.com/2014/02/17/building-responsible-visualizations-d3-js/
After you update your scales, only thing left to resize your circles would be something like this:
/* Force D3 to recalculate and update the points */
svg.selectAll('circle')
.attr('cx', function (d) { return xScale(d.x); })
.attr('cy', function (d) { return yScale(d.y); })
.attr('r', 4);

How to add a highlight mark/area to a chart?

I have a time series chart created using D3 js. I wanted to add highlight areas for certain time intervals to show certain activity occurred during that particular time (there will be different types of activities so each highlight mark will have different color based on its type). I want this highlight area to cover the whole chart vertically from top to bottom.
Here is a sample:
I came across this question which shows how to do it using highcharts.
As of now I use another charting library and I draw an area chart whenever I want to display such highlight areas. Is there a better way to do it using d3 js or should I draw a set of area charts?
I saw this question once. Time for example.
You can combine area and line chart together.
// y.domain()[1] so area is drawn to cover all chart
var area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.x_axis); })
.y0(height)
.y1(function(d) { return y(y.domain()[1]); });
var line = d3.svg.line()
.x(function(d) { return x(d.x_axis); })
.y(function(d) { return y(d.y_axis); });
Here's an example of AAPL stock chart with highlight from 2012-04-13 to 2012-04-17.
http://vida.io/documents/TzcZJX4itBebKciQZ
Full code:
https://gist.github.com/dnprock/dea634bfdb3c33149c61

Categories