Replace a Canvas Pie Chart Onclick - javascript

I have a pie chart created using chart.js
Here is the code for that:
var pieChartCanvas = $("#pieChart").get(0).getContext("2d");
var pieChart = new Chart(pieChartCanvas);
var PieData = [
{
value: 700,
color: "#f56954",
highlight: "#f56954",
label: "Chrome"
},
{
value: 500,
color: "#00a65a",
highlight: "#00a65a",
label: "IE"
},
{
value: 400,
color: "#f39c12",
highlight: "#f39c12",
label: "FireFox"
}
pieChart.Doughnut(PieData);
<canvas id="pieChart" style="width:60%; height:60%;"></canvas>
I want to create a few different pie charts representing different information but only want to ever display one pie chart at a time. So when i click on a drop down menu i want another pie chart to appear. Basically using the same code as above but changing the information in the pieData[].
The code for changing using the list is
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
<li>Device</li>
</ul>
Is there any way to do this?

Keeping in mind that only data will be changed because you want the same canvas for everything, you can create a function which draw the data on the canvas everytime is called (See the function receive as first parameter the data that will be displayed in the canvas)
function selectData(id){
if(id == 1){
var data = []; //whatever i want to draw when option 1 is selected!
DrawChart(data);
}
if(id == 2){
var data = []; //whatever i want to draw when option 2 is selected!
DrawChart(data);
}
}
function DrawChart(data){
var pieChartCanvas = $("#pieChart").get(0).getContext("2d");
var pieChart = new Chart(pieChartCanvas).Pie(data);
//Demo with official documentation http://www.chartjs.org/docs/
//var myPieChart = new Chart(ctx[0]).Pie(data,options);
//var myDoughnutChart = new Chart(ctx[1]).Doughnut(data,options);
}
so, you are not using a html Select widget, you are using a UL for this, you can use :
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
<li>Browsers</li>
<li>Other things</li>
</ul>
Although you can design a better mode to solve your problem, this is a quick solution that will help you to understand how to draw data dinamically with Chart.js

Related

c3.js set onClick property in chart generated from another function

My goal is to get 3 charts, with the most recently selected series in the first chart updating the second chart, and the most recently selected series in the second chart updating the third chart.
I start by setting up 3 divs:
<div id="chart1"></div>
<div id="chart2"></div>
<div id="chart3"></div>
I then generate 3 charts like so (essentially the same, but with different detail levels in the source data):
var chart1 = c3.generate({
bindto: document.getElementById('chart1'),
data: {
x: 'date',
url: 'file1.csv'
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d',
count: 8
},
label: "Date"
},
y: {
label: "Y Label"
}
},
// irrelevant options removed
legend: {
item: {
onclick: (id) => {
chart1.toggle(id);
chart_options2.data.url = 'file2_'+ id +'.csv';
if(chart1.data.shown(id).length == 1 ){
generateChart2(id);
}
}
}
}
});
var chart2 = c3.generate({
bindto: document.getElementById('chart2'),
// etc.
var chart3 = c3.generate({
bindto: document.getElementById('chart3'),
// etc.
The function generateChart2() will use the id of the selected series in chart1 to generate a new chart in the place of chart2. Likewise I have a similar function generateChart3() which will use the id of the selected series in chart2 to generate a new chart in the place of chart3. These functions look like this:
function generateChart2(id) {
c3.generate(chart_options2);
};
With chart_options being identical to the original set up options, except for the updated file source (see chart_options2.data.url = 'file2_'+ id +'.csv'; above).
Initially, these all seem to work ok. The problem arises when a new chart2 is created using the generateChart2() function, and the onclick property no longer seems to work for certain things. Testing with console.log, the onclick still seems to be called, and I can update the chart options var, but I can't use any of the other commands:
onclick: function (id) {
console.log('test'); // returns 'test'
chart2.toggle(id); // doesn't work
chart_options3.data.url = 'file3_'+ id +'.csv'; // works
if(chart2.data.shown(id).length == 1 ){
generateChart3(id); // doesn't work
}
I suspect it has something to do with the namespace, or how I'm using the chart names, or how I'm calling the function. I've spent a couple of days looking at this problem, but all my research hasn't really made it much clearer which direction I should be looking in.
EDIT: I found a workaround, which makes sense for my use case, but doesn't help me learn what I was doing wrong. Now instead of reusing c3.generate to dynamically create a new chart every time a series is selected in the previous chart, I am using unload() and load(). This seems to be working well, but I would very much appreciate an explanation or clarification of what I was doing wrong the first time. Updated code:
onclick: function (id) {
chart1.toggle(id);
if(chart1.data.shown(id).length == 1 ){
chart2.unload();
setTimeout(function () {
chart2.load({
url: 'file2_'+ id +'.csv'
});
}, 1000);
}
}

How to create custom legend in ChartJS

I need to create custom legend for my donut chart using ChartJS library.
I have created donut with default legend provided by ChartJS but I need some modification.
I would like to have value above the car name. Also I don't like sticky legend I want to have it separate from donut so I can change the style for fonts, boxes (next to the text "Audi" for example)
I know there is some Legend generator but I'm not sure how to use it with VueJS - because I'm using VueJS as a framework
This is how my legend looks like now - http://imgur.com/a/NPUoi
My code:
From Vue component where I import a donut component:
<div class="col-md-6">
<div class="chart-box">
<p class="chart-title">Cars</p>
<donut-message id="chart-parent"></donut-message>
</div>
</div>
Javascript:
import { Doughnut } from 'vue-chartjs'
export default Doughnut.extend({
ready () {
Chart.defaults.global.tooltips.enabled = false;
Chart.defaults.global.legend.display = false;
this.render({
labels: ['Audi','BMW','Ford','Opel'],
datasets: [
{
label: 'Cars',
backgroundColor: ['#35d89b','#4676ea','#fba545','#e6ebfd'],
data: [40, 30, 20, 10]
}
]
},
{
responsive: true,
cutoutPercentage: 75,
legend: {
display: true,
position: "right",
fullWidth: true,
labels: {
boxWidth: 10,
fontSize: 14
}
},
animation: {
animateScale: true
}
})
}
});
I'm having the same problem trying to understand the documentation and this link might clarify the process of customize the legends:
https://codepen.io/michiel-nuovo/pen/RRaRRv
The trick is to track a callback to build your own HTML structure and return this new structure to ChartJS.
Inside the options object:
legendCallback: function(chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend">');
for (var i = 0; i < chart.data.datasets[0].data.length; i++) {
text.push('<li><span style="background-color:' +
chart.data.datasets[0].backgroundColor[i] + '">');
if (chart.data.labels[i]) {
text.push(chart.data.labels[i]);
}
text.push('</span></li>');
}
text.push('</ul>');
return text.join("");
}
Second, you need a container to insert the new html and using the method myChart.generateLegend() to get the customized html:
$("#your-legend-container").html(myChart.generateLegend());
After that, if you need, track down the events:
$("#your-legend-container").on('click', "li", function() {
myChart.data.datasets[0].data[$(this).index()] += 50;
myChart.update();
console.log('legend: ' + data.datasets[0].data[$(this).index()]);
});
$('#myChart').on('click', function(evt) {
var activePoints = myChart.getElementsAtEvent(evt);
var firstPoint = activePoints[0];
if (firstPoint !== undefined) {
console.log('canvas: ' +
data.datasets[firstPoint._datasetIndex].data[firstPoint._index]);
}
else {
myChart.data.labels.push("New");
myChart.data.datasets[0].data.push(100);
myChart.data.datasets[0].backgroundColor.push("red");
myChart.options.animation.animateRotate = false;
myChart.options.animation.animateScale = false;
myChart.update();
$("#your-legend-container").html(myChart.generateLegend());
}
}
Another solution that I found, if you don't need to change the HTMl structure inside the legend, you can just insert the same HTML in your legend container and customize it by CSS, check this another link:
http://jsfiddle.net/vrwjfg9z/
Hope it works for you.
You can extract the legend markup.
data () {
return {
legendMarkup: ''
}
},
ready () {
this.legendMarkup = this._chart.generateLegend()
}
And in your template you can output it.
<div class="legend" ref="legend" v-html="legendMarkup"></div>
this._chart is the internal chartjs instance in vue-chartjs. So you can call all chartjs methods which are not exposed by vue-chartjs api over it.
However you can also use the legend generator. The usage is the same in vue. You can pass in the options, use callbacks etc.
please check this documentation
.
Legend Configuration
The chart legend displays data about the datasets that area appearing on the chart.
Configuration options
Position of the legend. Options are:
'top'
'left'
'bottom'
'right'
Legend Item Interface
Items passed to the legend onClick function are the ones returned from labels.generateLabels. These items must implement the following interface.
{
// Label that will be displayed
text: String,
// Fill style of the legend box
fillStyle: Color,
// If true, this item represents a hidden dataset. Label will be rendered with a strike-through effect
hidden: Boolean,
// For box border. See https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap
lineCap: String,
// For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
lineDash: Array[Number],
// For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
lineDashOffset: Number,
// For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
lineJoin: String,
// Width of box border
lineWidth: Number,
// Stroke style of the legend box
strokeStyle: Color
// Point style of the legend box (only used if usePointStyle is true)
pointStyle: String
}
Example
The following example will create a chart with the legend enabled and turn all of the text red in color.
var chart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
legend: {
display: true,
labels: {
fontColor: 'rgb(255, 99, 132)'
}
}
}
});
Custom On Click Actions
It can be common to want to trigger different behaviour when clicking an item in the legend. This can be easily achieved using a callback in the config object.
The default legend click handler is:
function(e, legendItem) {
var index = legendItem.datasetIndex;
var ci = this.chart;
var meta = ci.getDatasetMeta(index);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
// We hid a dataset ... rerender the chart
ci.update();
}
Lets say we wanted instead to link the display of the first two datasets. We could change the click handler accordingly.
var defaultLegendClickHandler = Chart.defaults.global.legend.onClick;
var newLegendClickHandler = function (e, legendItem) {
var index = legendItem.datasetIndex;
if (index > 1) {
// Do the original logic
defaultLegendClickHandler(e, legendItem);
} else {
let ci = this.chart;
[ci.getDatasetMeta(0),
ci.getDatasetMeta(1)].forEach(function(meta) {
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
});
ci.update();
}
};
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
legend: {
}
}
});
Now when you click the legend in this chart, the visibility of the first two datasets will be linked together.
HTML Legends
Sometimes you need a very complex legend. In these cases, it makes sense to generate an HTML legend. Charts provide a generateLegend() method on their prototype that returns an HTML string for the legend.
To configure how this legend is generated, you can change the legendCallback config property.
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
legendCallback: function(chart) {
// Return the HTML string here.
}
}
});

HighChart : plot line click event for multiple chart

I am using highchart for some drilldown functions.
I having a function to let the user click on an area plot and add a line. But then i found out my function has a bug in it. There's should be only one red line between those charts, but when the user click on the other chart the existing red line on the first chart is not removing.
The belowing is the function my charts sharing.
var myPlotLineId = "myPlotLine";
addPlotLine = function(evt) {
var point = evt.point;
var xValue = point.x;
var xAxis = point.series.xAxis;
Highcharts.each(xAxis.plotLinesAndBands, function(p) {
if (p.id === myPlotLineId) {
p.destroy();
}
});
xAxis.addPlotLine({
value: xValue,
width: 1,
color: 'red',
id: myPlotLineId
});
};
It should only allow one red line since i am using ID.
The below is the current situation.
Since i am using id for the plotline is shouldn't allow two line, please see my example:
http://jsfiddle.net/Xm4vW/74/
I want only ONE RED LINE in total out of many charts
UPDATE 1 :
I have tried redraw() in the new demo :
http://jsfiddle.net/Xm4vW/80/
but it doesn't help.
Please do let me know if the question is not clear enough.
There is nothing like 'Highcharts.each(xAxis.plotLinesAndBands, function(p) '. Iterate charts by loop and use 'removePlotLine(PlotLineID)' instead of 'destroy()':
for(i=0;i<Highcharts.charts.length; i++){
var chart=Highcharts.charts[i];
chart.xAxis[0].removePlotLine('myPlotLineId');
}
And set id in parenthesis:
id: 'myPlotLineId'
here is jsfiddle http://jsfiddle.net/asadsarwar89/bh4kz9rw/

Organizing graph options in Google Charts

I'm creating a handful of pie charts using Google Charts. The majority of the graph options for the charts I'm creating are the same, except the titles. Is it possible to maintain a default set of options but write certain specific options for each graph (in this case, I just need to set a title).
Here's an example of the code I'm using:
var graphOptions = {
is3D: true,
pieSliceText: 'label',
colors: ['#F9B641', '#FBCB75', '#FCE1B0', '#FFF8EB', '#FFFFFF'],
backgroundColor: 'transparent',
titleTextStyle: {
color: '#FFF'
},
legend: {
textStyle: {
color: '#FFF'
}
},
chartArea: {
width: '90%',
height: '80%'
}
};
function pieChart1() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Gender', 'Number'],
['Male', 216],
['Female', 238]
]);
// Create and draw the visualization.
var chart = new google.visualization.PieChart(document.getElementById('pieChart1'));
chart.draw(data, graphOptions);
}
function pieChart2() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Gender', 'Number'],
['Male', 116],
['Female', 98]
]);
// Create and draw the visualization.
var chart = new google.visualization.PieChart(document.getElementById('pieChart2'));
chart.draw(data, graphOptions);
}
How would I go about setting the title option for each graph while still pulling the options from graphOptions?
As David explained, you can create an options object, and then edit properties of that object individually.
Here is a jsfiddle that shows it in action.
Note: you cannot see the titles because the BG and font color is white. Just do a ctrl+a to select everything and see them hidden there
Basically, you create a variable both functions can access (in your case graphOptions). In each function you set a new variable called options to equal graphOptions. You can then change the title property of the options variable to whatever you want without changing your default options template graphOptions, and use the options variable to draw the graph.
For your code, that means adding this code to each function:
var options = graphOptions;
options.title = "Pie Chart X"
You can change the title to whatever is appropriate, different for each graph. Then in the graph draw command, you change graphOptions to options to get
chart.draw(data, options);
Normally you'd do:
var options = { title: 'My Chat Title' };
In your case add title to your graphOptions object then do:
graphOptions.title = "The New Title";
for each graph.

Pie chart using flot

I am using Jquery Flot to create a pie chart based on three different values, pause, nopause and sleeping. Initially it draws th pie chart correctly but after some redraw it gives me the following error.
Could not draw pie with labels contained inside canvas
My code is
Lecturer.socket.onmessage = function (message) {
var str = message.data;
var msg = str.split(":");
if(msg[0] == 'pause'){
var pause = parseInt(msg[1]);
var noPause = parseInt(msg[2]);
var sleeping = parseInt(msg[3]);
var data = [
{label: "Pause", data:pause},
{label: "No Pause", data:noPause},
{label: "Sleeping", data:sleeping}
];
var options = {
series: {
pie: {show: true}
},
legend: {
show: false
}
};
$.plot($("#pie-placeholder"), data, options);
}
};
HTML is
<div id="live-placeholder" class="flot"></div>
All the require js libraries are included. What I m doing wrong? Any Help ?
Thanks
You've got two problems:
1.) your placeholder div id doesn't match the $.plot call. live-placeholder != pie-placeholder.
2.) You don't need to calculate the percents yourself. Flot will do it internally.
See a working fiddle here.

Categories

Resources