I've got a question regard Chart.js.
I've drawn multiple piecharts using the documentation provided. I was wondering if on click of a certain slice of one of the charts, I can make an ajax call depending on the value of that slice?
For example, if this is my data
var data = [
{
value: 300,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
},
{
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow"
}
],
is it possible for me to click on the Red labelled slice and call a url of the following form:
example.com?label=red&value=300? If yes, how do I go about this?
Update: As #Soham Shetty comments, getSegmentsAtEvent(event) only works for 1.x and for 2.x getElementsAtEvent should be used.
.getElementsAtEvent(e)
Looks for the element under the event point, then returns all elements
at the same data index. This is used internally for 'label' mode
highlighting.
Calling getElementsAtEvent(event) on your Chart instance passing an
argument of an event, or jQuery event, will return the point elements
that are at that the same position of that event.
canvas.onclick = function(evt){
var activePoints = myLineChart.getElementsAtEvent(evt);
// => activePoints is an array of points on the canvas that are at the same position as the click event.
};
Example: https://jsfiddle.net/u1szh96g/208/
Original answer (valid for Chart.js 1.x version):
You can achieve this using getSegmentsAtEvent(event)
Calling getSegmentsAtEvent(event) on your Chart instance passing an
argument of an event, or jQuery event, will return the segment
elements that are at that the same position of that event.
From: Prototype Methods
So you can do:
$("#myChart").click(
function(evt){
var activePoints = myNewChart.getSegmentsAtEvent(evt);
/* do something */
}
);
Here is a full working example:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-2.0.2.js"></script>
<script type="text/javascript" src="Chart.js"></script>
<script type="text/javascript">
var data = [
{
value: 300,
color:"#F7464A",
highlight: "#FF5A5E",
label: "Red"
},
{
value: 50,
color: "#46BFBD",
highlight: "#5AD3D1",
label: "Green"
},
{
value: 100,
color: "#FDB45C",
highlight: "#FFC870",
label: "Yellow"
}
];
$(document).ready(
function () {
var ctx = document.getElementById("myChart").getContext("2d");
var myNewChart = new Chart(ctx).Pie(data);
$("#myChart").click(
function(evt){
var activePoints = myNewChart.getSegmentsAtEvent(evt);
var url = "http://example.com/?label=" + activePoints[0].label + "&value=" + activePoints[0].value;
alert(url);
}
);
}
);
</script>
</head>
<body>
<canvas id="myChart" width="400" height="400"></canvas>
</body>
</html>
Using Chart.JS version 2.1.3, answers older than this one aren't valid anymore.
Using getSegmentsAtEvent(event) method will output on console this message:
getSegmentsAtEvent is not a function
So i think it must be removed. I didn't read any changelog to be honest. To resolve that, just use getElementsAtEvent(event) method, as it can be found on the Docs.
Below it can be found the script to obtain effectively clicked slice label and value. Note that also retrieving label and value is slightly different.
var ctx = document.getElementById("chart-area").getContext("2d");
var chart = new Chart(ctx, config);
document.getElementById("chart-area").onclick = function(evt)
{
var activePoints = chart.getElementsAtEvent(evt);
if(activePoints.length > 0)
{
//get the internal index of slice in pie chart
var clickedElementindex = activePoints[0]["_index"];
//get specific label by index
var label = chart.data.labels[clickedElementindex];
//get value by index
var value = chart.data.datasets[0].data[clickedElementindex];
/* other stuff that requires slice's label and value */
}
}
Hope it helps.
Chart.js 2.0 has made this even easier.
You can find it under common chart configuration in the documentation. Should work on more then pie graphs.
options:{
onClick: graphClickEvent
}
function graphClickEvent(event, array){
if(array[0]){
foo.bar;
}
}
It triggers on the entire chart, but if you click on a pie the model of that pie including index which can be used to get the value.
Working fine chartJs sector onclick
ChartJS : pie Chart - Add options "onclick"
options: {
legend: {
display: false
},
'onClick' : function (evt, item) {
console.log ('legend onClick', evt);
console.log('legd item', item);
}
}
I was facing the same issues since several days, Today i have found the solution. I have shown the complete file which is ready to execute.
<html>
<head><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.js">
</script>
</head>
<body>
<canvas id="myChart" width="200" height="200"></canvas>
<script>
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
onClick:function(e){
var activePoints = myChart.getElementsAtEvent(e);
var selectedIndex = activePoints[0]._index;
alert(this.data.datasets[0].data[selectedIndex]);
}
}
});
</script>
</body>
</html>
If using a Donught Chart, and you want to prevent user to trigger your event on click inside the empty space around your chart circles, you can use the following alternative :
var myDoughnutChart = new Chart(ctx).Doughnut(data);
document.getElementById("myChart").onclick = function(evt){
var activePoints = myDoughnutChart.getSegmentsAtEvent(evt);
/* this is where we check if event has keys which means is not empty space */
if(Object.keys(activePoints).length > 0)
{
var label = activePoints[0]["label"];
var value = activePoints[0]["value"];
var url = "http://example.com/?label=" + label + "&value=" + value
/* process your url ... */
}
};
If you are using TypeScript, the code is a little funky because there is no type inference, but this works to get the index of the data that has been supplied to the chart:
// events
public chartClicked(e:any):void {
//console.log(e);
try {
console.log('DS ' + e.active['0']._datasetIndex);
console.log('ID ' + e.active['0']._index);
console.log('Label: ' + this.doughnutChartLabels[e.active['0']._index]);
console.log('Value: ' + this.doughnutChartData[e.active['0']._index]);
} catch (error) {
console.log("Error In LoadTopGraph", error);
}
try {
console.log(e[0].active);
} catch (error) {
//console.log("Error In LoadTopGraph", error);
}
}
To successfully track click events and on what graph element the user clicked, I did the following in my .js file I set up the following variables:
vm.chartOptions = {
onClick: function(event, array) {
let element = this.getElementAtEvent(event);
if (element.length > 0) {
var series= element[0]._model.datasetLabel;
var label = element[0]._model.label;
var value = this.data.datasets[element[0]._datasetIndex].data[element[0]._index];
}
}
};
vm.graphSeries = ["Series 1", "Serries 2"];
vm.chartLabels = ["07:00", "08:00", "09:00", "10:00"];
vm.chartData = [ [ 20, 30, 25, 15 ], [ 5, 10, 100, 20 ] ];
Then in my .html file I setup the graph as follows:
<canvas id="releaseByHourBar"
class="chart chart-bar"
chart-data="vm.graphData"
chart-labels="vm.graphLabels"
chart-series="vm.graphSeries"
chart-options="vm.chartOptions">
</canvas>
var ctx = document.getElementById('pie-chart').getContext('2d');
var myPieChart = new Chart(ctx, {
// The type of chart we want to create
type: 'pie',
});
//define click event
$("#pie-chart").click(
function (evt) {
var activePoints = myPieChart.getElementsAtEvent(evt);
var labeltag = activePoints[0]._view.label;
});
You can add in the options section an onClick function, like this:
options : {
cutoutPercentage: 50, //for donuts pie
onClick: function(event, chartElements){
if(chartElements){
console.log(chartElements[0].label);
}
},
},
the chartElements[0] is the clicked section of your chart, no need to use getElementsAtEvent anymore.
It works on Chart v2.9.4
I have an elegant solution to this problem. If you have multiple dataset, identifying which dataset was clicked gets tricky. The _datasetIndex always returns zero.
But this should do the trick. It will get you the label and the dataset label as well.
Please note ** this.getElementAtEvent** is without the s in getElement
options: {
onClick: function (e, items) {
var firstPoint = this.getElementAtEvent(e)[0];
if (firstPoint) {
var label = firstPoint._model.label;
var val = firstPoint._model.datasetLabel;
console.log(label+" - "+val);
}
}
}
Within options place your onclick and call the function you need as an example the ajax you need, I'll leave the example so that every click on a point tells you the value and you can use it in your new function.
options: {
plugins: {
// Change options for ALL labels of THIS CHART
datalabels: {
color: 'white',
//backgroundColor:'#ffce00',
align: 'start'
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
fontColor: "white"
},gridLines: {
color: 'rgba(255,255,255,0.1)',
display: true
}
}],
xAxes: [{
ticks: {
fontColor: "white"
},gridLines: {
display: false
}
}]
},
legend: {
display: false
},
//onClick: abre
onClick:function(e){
var activePoints = myChart.getElementsAtEvent(e);
var selectedIndex = activePoints[0]._index;
alert(this.data.datasets[0].data[selectedIndex]);
}
}
Related
I'm trying to display a stock chart on the webpage when it is opened, but it won't display unless i press f12
I've already tried including the code inside a function and displaying the chart when a button is pressed but it also doesn't seem to work
<script type="text/javascript">
var highlist = [];
var lowlist = [];
var datelist = [];
$.getJSON("https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&apikey=G9UIQ9K1TRVBHHME", function(json) {
var times = json["Time Series (Daily)"];
for(var time in times)
{
var stock_info = times[time];
var highItem = stock_info["2. high"];
var lowItem = stock_info["3. low"];
highlist.push(highItem);
lowlist.push(lowItem);
datelist.push(time);
}
});
var ctx = document.getElementById("lineChart").getContext('2d');
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: datelist,
datasets: [{
label: "My First dataset",
label: "High",
backgroundColor: [
'rgba(204, 204, 255, .2)',
],
borderColor: [
'rgba(51, 51, 255, .7)',
],
borderWidth: 2,
data: highlist
},
{
label: "Low",
backgroundColor: [
'rgba(0, 137, 132, .2)',
],
borderColor: [
'rgba(0, 10, 130, .7)',
],
data: lowlist
}]
},
});
</script>
Expect the chart to show but nothing is displaying unless f12 is pressed
The getJson is an asynchronous function, so JS will send a request and then draw your chart before it gets a response.
Put all the chart stuff inside a function, and then call that function after the for loop inside your getJson callback.
import Chart from "chart.js"
let AnalyticsChart = {
buildChart() {
let ctx = document.getElementById("analyticsChart");
let labels = ["sent", "delivered", "undelivered", "clicks"];
let total_sent = parseInt(document.getElementById("total-sent").dataset.totalSent);
let delivered = parseInt(document.getElementById("deilvered-count").dataset.deliveredCount);
let undelivered = parseInt(document.getElementById("undelivered-count").dataset.undeliveredCount);
let clicks = parseInt(document.getElementById("total-clicks").dataset.totalClicks);
let counts = [total_sent, delivered, undelivered, clicks]
let chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: counts,
backgroundColor: [
'rgba(54, 162, 235, 0.5)',
'rgba(255, 206, 86, 0.5)',
'rgba(255, 99, 132, 0.5)',
'rgba(75, 192, 192, 0.5)'
]
}]
},
options: {
}
});
},
update(){
}
}
export default AnalyticsChart
in this code I want to add update function to update chart.
I want to pass chart variable to update function how can I do this?
like this
update(chart) {
let total_sent = parseInt(document.getElementById("total-sent").dataset.totalSent);
let delivered = parseInt(document.getElementById("deilvered-count").dataset.deliveredCount);
let undelivered = parseInt(document.getElementById("undelivered-count").dataset.undeliveredCount);
let clicks = parseInt(document.getElementById("total-clicks").dataset.totalClicks);
let counts = [total_sent, delivered, undelivered, clicks]
chart.data.datasets.forEach((dataset) => {
dataset.data.push(counts) # How can I put individual counts value?
});
chart.update();
}
My questions
1. How can I pass chart variable in buildChart() to update function as parameter.
2. how can I put individual counts element in dataset.data.push(counts)?
I'm not familiar the way of your implement.
But it seems like java, so you need member variable, and access them using this from each function.
let AnalyticsChart = {
chart: null,
buildChart() {
/** omit **/
this.chart = new Chart(ctx, {
~
update() {
/** omit **/
this.chart.update();
I'm sorry I don't quite understand the question2.
Do you want to push the data, rather than update? If so, you can't do it just prepare the value. (I mean, you need labels, background...)
If you just want to update the chart, that is a piece of cake
this.chart.data.datasets.forEach((dataset) => {
dataset.data = counts;
});
Remember, you have one datasets.
If datasets is not dynamically, I think there's no need to loop.
this.chart.data.datasets[0].data = counts;
I'm adding a chart in a website and I'm having a weird issue with chart.js. I'm loading the data from 2 arrays that are created when the page is loaded from a json file.
The issue is that the data it's not showing until I click on the label of the chart 2 times. At load, there is no info, 1st click x labels are showing up and in 2nd click both, x labels and data are showing up. After that, clicking on the label of the dataset work as expected.
I assumed my problem was that I was loading the data before the chart exists, so, my idea was to encapsulate everything in a function and call it when clicking a button that shows the chart, but it's keeping doing the same thing. How would you fix it?
Here is my html related code:
<div class="popup">
<span class="popuptrend" id="myPopup"><canvas id="myChart" width="auto" height="400"></canvas></span>
</div>
And my JS code:
$(function(){
$("#showTrend").click(function(){
createChart();
var popup = document.getElementById("myPopup");
popup.classList.toggle("show");
});
});
function createChart(){
var labels = [];
var dataValue = [];
$.getJSON("./resources/chart.json", function(jsonData) {
var index = 0;
for (var key in jsonData) {
if(index == 0){ // SKIP FISRT ITEM
index++;
}else{
labels.push(key);
dataValue.push(parseFloat(jsonData[key]));
}
}
});
var dataVar = {
labels: labels,
datasets:
[{
label: "Value",
backgoundColor: 'rgba(255, 0, 0, 0.2)',
borderColor: 'rgba(255, 0, 0, 0.8)',
borderWith: 1,
data: dataValue
}]
};
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: dataVar,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
}
And a extract from my data json file:
{
"15/04/2017":"67.34375",
"16/04/2017":"67.3203125",
}
And a gif of the behaviour.
Thanks!
Since $.getJSON() method is asynchronous, you should construct your chart inside itÂ's callback function, like so :
...
$.getJSON("./resources/chart.json", function(jsonData) {
var index = 0;
for (var key in jsonData) {
if (index == 0) { // SKIP FISRT ITEM
index++;
} else {
labels.push(key);
dataValue.push(parseFloat(jsonData[key]));
}
}
var dataVar = {
labels: labels,
datasets: [{
label: "Value",
backgoundColor: 'rgba(255, 0, 0, 0.2)',
borderColor: 'rgba(255, 0, 0, 0.8)',
borderWith: 1,
data: dataValue
}]
};
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: dataVar,
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
});
...
Hopefully, this will solve your problem.
As I posted before as a comment, try doing like this:
$.getJSON(...).done(var dataVar....)
I'm currently having a problem which seems to be well known already, but of the answer provided none have worked so far for me.
Whenever I'm hovering over the line in a linegraph, the chart changes back to a chart displayed before as shown in the GIF below:
https://i.stack.imgur.com/cmknf.gif
The solution which seemed the best to me so far is destroying the chart before creating a new one if it's not the first set of data. (bool 'first' and chart 'pauzeAmountChart' are global variables)
function setupAvgPauseGraph(currVideo, currData) {
if (!first) {
pauzeAmountChart.destroy();
}
first = false;
var ctx = document.getElementById("pauzeduurChart");
...
avgPauseChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Gemiddelde pauzeduur / seconde',
data: data,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [
{ticks: {min: 0, stepSize: step}}],
xAxes: [
{scaleLabel: {display: true, labelString: 'Seconden in video'}}]
},
elements: {point: {radius: 0}}
}
});
}
However, when it's not the first dataset, thus getting to the line 'pauzeAmountChart.destroy()' AND which means the chart already has been initialized and filled with data before, I get this error:
http://prntscr.com/e57x4a
I'm unfortunately not sure what this error means, and Google didn't help me any further either.
Also, when I keep switching between the data the error appears again + 1 more time compared to the previous time the error appeared. Which means it's not actually destroying the graph? (So try #x to show the data gives x errors)
Please let me know if you need any more information.
Thank you in advance!
[EDIT]
Thanks to Guus Punt it's fixed! With a few adjustments, it works now. See below for solution:
function setupPauzeAmountGraph(currVideo, currData) {
var ctx = document.getElementById("aantalPauzesChart");
...
if (pauzeAmountChart != undefined) {
pauzeAmountChart.chart.config.data.labels = labels;
pauzeAmountChart.chart.config.data.datasets[0].data = data;
pauzeAmountChart.update();
} else {
pauzeAmountChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Aantal pauzes / seconde',
data: data,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [
{ticks: {min: 0, stepSize: step}}],
xAxes: [
{scaleLabel: {display: true, labelString: 'Seconden in video'}}]
},
elements: {point: {radius: 0}}
}
});
}
}
I would need to run your example to be sure but maybe the following would help.
Instead of destroying the chart you can add and remove datasets,
Remove dataset before adding new data
data.labels = []; //Empty label array
data.datasets.splice(0, 1);//Removes first dataset
Add new dataset and labels
Update chart
pauzeAmountChart.update();
I have a working example which retrieves new data from a webapi and updates every 10 seconds, if this isnt sufficient
Here is my chart creation
createChart = function (name, contributions, idArray) {
globalIdArray = idArray;
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: name,
datasets: [{
label: "Contributions",
data: contributions,
backgroundColor: [
'rgba(0, 255, 0, 0.2)',
'rgba(0, 255, 0, 0.2)',
'rgba(0, 255, 0, 0.2)',
'rgba(0, 255, 0, 0.2)',
'rgba(0, 255, 0, 0.2)'
]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
onClick: handleClick,
onHover: handleHover
}
});
This is the HTML, everything is JavaScript and resides inside the canvas element.
<canvas chart-hover="onHover" id="myChart" width="200" height="200"></canvas>
I made it so when I click on a bar they act as a "drill in" and take my a page with more details. To do that I used this code:
function handleClick(e) {
debugger;
var activeElement = myChart.getElementAtEvent(e);
var designerId = _idArray[activeElement[0]._index];
window.location.href = "/Display/search/index?designerId=" + designerId;
}
I'd like to make it so my cursor changes to a pointer to let the user know they can click the bar (as it would normally change with a link). I saw some examples of this on Stack Overflow but they were from the last year or two, the posts included comments asking for an updated version but no solutions.
Here is another post I saw which I believe is the same thing I am trying to accomplish but it didn't work for me.
How to change cursor style to pointer on hovering over points of the chart?
Does anyone know of how I can implement this, using the most recent live version of ChartJS?
I needed the cursor to change only when over a bar or point on a line chart so came up with this simple solution. Place your function outside the chart declaration.
var chart = new Chart(ctx, {
data: {...},
options: {
onHover: graphHover
}
});
function graphHover(e, array) {
if(array.length > 0) {
e.target.style.cursor = 'pointer';
}else {
e.target.style.cursor = '';
}
}
there is a cursor property in css that you can set.
for example :
span.crosshair {
cursor: crosshair;
}
span.help {
cursor: help;
}
span.wait {
cursor: wait;
}
Please refer to this link for more information