Marker in BillboardJS on defocus - javascript

When hovering over a line in billboardjs you can see a marker which follows the mouse (a tall vertical line). Is there a function for putting a marker on the x-line which can be used without triggering an automatic marker via onmousemove/hovering over data-points?
var chart = bb.generate({
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
],
type: "line", // for ESM specify as: line()
},
bindto: "#lineChart"
});
https://naver.github.io/billboard.js/demo/#Chart.LineChart
So to exemplify. I use an onclick (in the data object) in the chart which defocuses the view and I still want the marker to remain.
So the code would look something like:
var chart = bb.generate({
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
],
type: "line", // for ESM specify as: line()
onclick: function (d) {
focusElsewhere()
showMarker(d.x)
}
},
bindto: "#lineChart"
});
So the question is if there is a function for this, or an obvious fix?
I have looked through https://naver.github.io/billboard.js/release/latest/doc/Chart.html but I may of course have missed something.

I found that using xgrids did the trick. I don't think that the documentation gives a good example of how to use it. But basically you can use the "value" field to give which point the line should be on and add a class to show different kinds of lines.
var chart = bb.generate({
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
],
type: "line", // for ESM specify as: line()
onclick: function (d) {
focusElsewhere()
this.xgrids.add({ value: d.x, class: "hover-line" }); //showMarker(d.x)
}
},
bindto: "#lineChart"
});
To remove the line or reset the billboard for continued use so to say, you can use
xgrids․remove({}) and add an object with some parameters of what kind of lines you want to remove.

Related

How to change the line color in billboard.js

I am novice with billboard.js, tried to do a very simple thing: changing the color of a line.
var chart = bb.generate({
data: {
columns: [
["data1", 30, 20, 50, 40, 60, 50],
["data2", 200, 130, 90, 240, 130, 220]
],
type: "line",
bindto: "#dataColor"
});
chart.data.colors({data1:'orange'});
In this example, I can change the color of data1 in orange, but data1 is not a variable, I want something like this:
var lab1="toto",lab2="titi";
var chart = bb.generate({
data: {
columns: [
[lab1, 30, 20, 50, 40, 60, 50],
[lab2, 200, 130, 90, 240, 130, 220]
],
type: "line",
bindto: "#dataColor"
});
chart.data.colors({lab1:'orange'});
But this doesn't work, I have to hard code the value of lab1: chart.data.colors({toto:'orange'})
Try enclosing the it inside square brackets. This should replace it with the string value of lab1.
chart.data.colors({[lab1]:'orange'});
From MDN
Starting with ECMAScript 2015, the object initializer syntax also supports computed property names. That allows you to put an expression in brackets [], that will be computed and used as the property name.
If you are not using ES2015, You can always do
var d = {};
d[lab1] = 'orange';
chart.data.colors(d);

How to use chart in JavaScript with large data set

I need to visualize the bar chart with Javascript. So I'm used C3 JS to visualize the chart. Simply I'm using this Bar chart as follows,
<div id="chart"></div>
<script>
var chart = c3.generate({
bindto: '#chart',
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
],
axes: {
data2: 'y2'
},
types: {
data2: 'bar'
}
},
axis: {
y: {
label: {
text: 'Y Label',
position: 'outer-middle'
},
tick: {
format: d3.format("$,") // ADD
}
},
y2: {
show: true,
label: {
text: 'Y2 Label',
position: 'outer-middle'
}
}
}
});
</script>
But the problem is when X-axis consists of the large data set Chart getting cramped. I have more than 700 data.
Have any possible way to avoid this? can I add scroll bar between primary and secondary X-axis?
Google, such a wonderfull thing ;)
https://c3js.org/samples/interaction_zoom.html
or this
C3 / D3 bar chart with horizontal scroll

C3js Stacked Bar Chart with a hidden bar

Scenario: I need to show a bar chart about payment details, how much the customers paid for a product using Card, Cheque or Cash. And also need to display the total value in a stacked bar chart.
var chart = c3.generate({
data: {
columns: [
['Cash', 30, 200, 100, 400, 150, 250],
['Card', 130, 100, 140, 200, 150, 50],
['Total', 160,300,240,600,300,300]
],
groups:[['Cash','Card']],
type: 'bar'
}
});
Output:
I need to show the Total value but not the bar and the legend. How can do this? Any advice would be helpful. Thank you.
You don't need the total dataset, you can alter the tooltip contents to calculate it on the fly (adapting the technique found in the answer here -> https://stackoverflow.com/a/36789099/368214)
var chart = c3.generate({
data: {
columns: [
['Cash', 30, 200, 100, 400, 150, 250],
['Card', 130, 100, 140, 200, 150, 50],
],
groups:[['Cash','Card']],
type: 'bar'
},
tooltip : {
contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
var total = d.reduce (function(subTotal,b) { return subTotal + b.value; }, 0);
d.push ({value: total, id: "Total", name: "Total", x:d[0].x , index:d[0].index});
return this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color);
}
}
});
The total value is calculated using .reduce to sum all the other values at that point. Then make a new data point for the tooltip called 'Total' using that value and pass it to the default renderer for drawing (this.getTooltipContent)
http://jsfiddle.net/vz1rwvwn/

Modify Donut Chart Slices in C3/D3

I have created a simple donut chart using c3.js. Here is the FIDDLE.
If you hover over a slice of the Donut it will stick out. I was wondering if it is possible for the slice to stick out by default without hovering over.
For example i want slice A, slice B, and C to stickout by default How can I do that?
Here is my Code
var currentSlice;
var chart = c3.generate({
data: {
x: 'x',
columns: [
['x', '2013-01-01', '2013-01-02', '2013-01-03', '2013-01-04', '2013-01-05', '2013-01-06'],
['A', 30, 200, 100, 400, 150, 250],
['B', 130, 100, 140, 200, 150, 50],
['C', 50, 100, 130, 240, 200, 150],
['D', 130, 100, 140, 200, 150, 50],
['E', 130, 150, 200, 300, 200, 100]
],
type: 'donut',
onclick: function (e) {
},
onmouseover: function (d, i) {
if(currentSlice !== void 0) {
'currentSlice'.attr("transform","scale(1)")
}
currentSlice = d3.select(i).attr("transform", "scale(1.1)");
},
onmouseout: function (d, i) {
}
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d',
centered: true,
position: 'inner-right'
}
}
},
bindto: '#dash',
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
},
pie: {
expand: true,
},
tooltip: {
grouped: false,
contents: function (data, defaultTitleFormat, defaultValueFormat, color) {
// console.log("Containt");
// console.log(data, defaultTitleFormat, defaultValueFormat, color);
return "<p style='border:1px solid red;'>" + data[0].value + "</p>";
}
}
});
c3js has two options, but both require a slight hack with 'setTimeout' to force our default scaling to happen after rendering and animation occur.
The onrendered function is available to set within the c3config object that one initializes the chart with. This function is triggered after a redraw is triggered but before visual rendering happens in the DOM. However, there is a hack to use setTimeout since it will create a separate callstack that will execute after the current callstack which in c3 happens to include redrawing the graph. (explanation of setTimeout to force logic to run after current callstack executes)
The load function exposes a done callback that is triggered after the elements are rendered to the DOM but before the animation finishes. So if one sets the initial scale transform in done, if the animations triggered by load are using the scale transform (which loading a pie chart appears to do), then the last keyframe of the animation will overwrite your modified scale back to scale(1). However, we can similarly use setTimeout to run our code after the current callstack (which includes animation) executes.
In exploring this, I created a generalized form of rby's answer, and I offer two alternative paths to setting default scales through the onrendered and done functions exposed in c3. (Fiddle):
var selected = ['A', 'B', 'C'];
var _ARC = '.c3-arc';
var _SCALING = '1.1';
function getCurrentlySelected() {
var _PREFIX = _ARC + '-';
return d3.selectAll(_PREFIX + selected.join(', ' + _PREFIX));
}
Within c3config object and onrendered through initialization:
var chart = c3.generate({
bindto: '#chart',
data: { ... },
onrendered: function() {
setTimeout(function() {
if (selected.length > 0) {
getCurrentlySelected().attr('transform', 'scale(' + _SCALING + ')');
}
}); // Notice we don't need a delay, just taking advantage to force our logic to happen after current callstack is executed
}
});
Also possible to use load with done after initialization:
chart.load({
columns: [
['A', 30, 200, 100, 400, 150, 250],
['B', 130, 100, 140, 200, 150, 50],
['C', 50, 100, 130, 240, 200, 150],
['D', 130, 100, 140, 200, 150, 50],
['E', 130, 150, 200, 300, 200, 100]
],
done: function() {
setTimeout(function() {
if (selected.length > 0) {
getCurrentlySelected().attr('transform', 'scale(' + _SCALING + ')');
}
}) // Notice we don't need a delay, just taking advantage to force our logic to happen after current callstack is executed
}
});
You can use setTimeout() to scale specific slices, once the chart is rendered. Here's one way:
setTimeout( function() {
d3.selectAll('.c3-arc-A, .c3-arc-B, .c3-arc-C').attr("transform", "scale(1.2)");
}, 5);
Place this call after your c3.generate() call.

C3JS bar chart with specific order

If I have a C3JS grouped bar chart defined like the following, how can I get the segments to stay in the order I've defined them instead of in ascending order by value? By default C3 will order them as 5, 10, 40, but I want it to remain as 10, 40, 5.
c3.generate({
bindto: '.active-loads',
data: {
columns: [
['Picking up future', 10],
['Enroute', 40],
['Delivered', 5]
],
type: 'bar',
groups: [
['Picking up future', 'Enroute', 'Delivered']
],
onclick: function(d) {
console.debug(d);
}
},
axis: {
rotated: true,
x: {
show: false
}
}
});
EDIT
Turns out it's as easy as specifying order: null in the data property.
C3js documentation has page for this : http://c3js.org/samples/data_order.html
You can order your data in following way :
var chart = c3.generate({
data: {
columns: [
['data1', 130, 200, 320, 400, 530, 750],
['data2', -130, 10, 130, 200, 150, 250],
['data3', -130, -50, -10, -200, -250, -150]
],
type: 'bar',
groups: [
['data1', 'data2', 'data3']
],
order: 'desc' // stack order by sum of values descendantly.
// order: 'asc' // stack order by sum of values ascendantly.
// order: null // stack order by data definition.
},
grid: {
y: {
lines: [{value:0}]
}
}
});
Also detailed explanation here too : http://c3js.org/reference.html#data-order
You can specify your function too :)

Categories