Double clicking on c3js line chart - javascript

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.

Related

Redrawing grid lines on a line chart (remove and redraw) in d3.js

I inherited a project that was using d3.js and one of the charts was a line chart; I had to make a lot of changes to it, one being adding grid lines, I did this like so:
grid_wrap = plot.append('g').classed('grid-wrapper', true);
//......
chart = function() {
//.....
valueScale.domain([0, settings.value_scale_max]).range([plot_height, 0]);
grid_wrap.append("g")
.attr("class", "grid")
.attr("width", grid_width)
.call(make_y_axis(valueScale)
.tickSize(-grid_width)
.tickFormat("")
);
//.....
}
Note the chart function above gets called on a redraw.
function make_y_axis(valueScale) {
return d3.axisLeft()
.scale(valueScale)
.ticks(5);
}
Now, this draws the grid lines fine, however whenever the window is resized it uses a resize event trigger to redraw the graphs, however whilst everything else redraws correctly my grid lines instead get duplicated over and over ending up with several .grid elements.
I checked out how the other code is handling it and I understand it this way:
There are also these threshold elements on the graph and they are built this way:
thresholds = plot.append('g').classed('thresholds', true);
chart = function() {
//.....
valueScale.domain([0, settings.value_scale_max]).range([plot_height, 0]);
thresholds = plot.select('.thresholds').selectAll('.threshold').data(chart.Thresholds);
Uses data to populate the threshold elements.
new_thresholds = thresholds.enter().append('g').attr('class', 'threshold');
Now, as I understand it, thresholds won't contain any elements on the first draw, but on redraws will contain the already existing elements.
new_thresholds will then work on this data and add needed new .threshold elements to match the amount needed in the dataset since we are using the enter function here.
new_thresholds.append('rect').classed('threshold-rect', true).attr('x', 0).attr('y', 0).attr('width', plot_width);
Adding elements to our newly created elements.
thresholds.exit().remove();
Then as I understand it this removes any extra elements that are too many compared to the dataset we provided?
//.....
}
So I guess what I am asking is how can I achieve the same thing with the grid lines since it's not working on a dataset?
I was overthinking it, all I had to do was add this:
grid_wrap.selectAll('.grid').remove();
above the below code...
grid_wrap.append("g")
.attr("class", "grid")
.attr("width", grid_width)
.call(make_y_axis(valueScale)
.tickSize(-grid_width)
.tickFormat("")
);
This makes sure any gridlines are removed before and hence when they get created it only ends up with the one being there.

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/

Hide x-axis labels but show tooltips in chart.js

I found many answers how to hide every nth label and yet still be able to show it in the tooltip. But there's a catch. If the label is very long, then the chart would be drawn somehow squished to the top of the canvas. It's logical. But is there any way to hide the labels, still show them in the tooltips and yet ignore them while calculating the y-values? So that the line can be drawn from top to bottom of the canvas?
Thank you for any advice!!
You can extend the line chart to do this. Adapted from Hide labels on x-axis ChartJS (which was for bar charts) with some unneeded code removed.
What we do is pretty simple, we first set the labels array to blanks, allow the initialization to happen and finally loop through the points for the (first) dataset and set the labels to the original labels.
Chart.types.Line.extend({
name: "LineAlt",
initialize: function(data){
var originalLabels = data.labels;
data.labels = data.labels.map(function() { return '' });
Chart.types.Line.prototype.initialize.apply(this, arguments);
this.datasets[0].points.forEach(function(bar, i) {
bar.label = originalLabels[i];
});
}
});
It's enough that you set the labels for the first dataset even if you have multiple datasets - when building a multiTooltip, the label is picked from the first dataset.
Fiddle - http://jsfiddle.net/xjchy2dn/

NVD3.js piechart use in Leaflet control

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.

Can't add anything to my d3 bar graph

Here is a simplified, for-the-public's-eyes version of my bar graph. I can't seem to add anything to it. I was following this tutorial trying to add the vertical lines from the x-axis and the text inside each bar to my graph, neither of which are showing up. Basically nothing really shows up that I try to add, but I was able to add the x-axis line which you can see in graph.js # line 65. You can see where I tried adding lines to the graph in my code at line 56 in graph.js. The x values are arbitrary as I was just trying to get them to show up. What am I doing wrong?
The problem is that your selector, "line", is not specific enough. There are already 'line' elements in the document; they form the axis ticks.
Because of that, your code is doing the following. It selects the existing line elements and binds the data your provided to those elements. Since those elements already existed, the enter() selection will be empty. This means that your append("line") command will never be executed:
var lines = svg.selectAll("line")
.data(data)
.enter().append("line")
You can provide more specificity by adding a class. For example the following should work:
var lines = svg.selectAll("line.rules")
.data(data)
.enter().append("line")
.attr("class", "rules");
More about the enter, update, and exit selections can be found in Mike's article Thinking with Joins.

Categories