I have a page full of charts that automatically generates all charts available (because the default page is "All Charts"). In it, there's a select department tag that will hide all charts other than those owned by the selected department. Here's my code:
$(window).load(function(){
$('#department').change(function(){
active_department($(this).val());
});
function active_department(department){
for(var i = 0; i < dept['namedept'].length; i++){
if(department!='All'){
$('.'+dept['namedept'][i]).hide(500);
} else {
if(typeof rCharts[dept['namedept'][i]] != 'undefined'){
$('.'+dept['namedept'][i]).show(500);
} else {
$('.no-chart-'+dept['namedept'][i]).hide(500);
}
}
}
if(typeof rCharts[department] != 'undefined'){
$('.'+department).show(500);
} else {
$('.no-chart-'+department).hide(500);
}
}
});
I want ChartJS animation to re-appear every time I select a department. So far I've tried easing, onProgress, and jQuery animate. none's working. Is it possible to re-animate the chart? If so, how?
From this answer and from the lack of options available in the Docs, it looks like the only feasible options would be these hacks:
redraw the chart with JS using new Chart or
change some minor configuration, or recreate an instance of the chart data and then call the update() method.
e.g.: Call the data through a function, and when you want the animation to happen, call the same function again. Because it now has a new array (even though it's the same data), the chart re-animates.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<button onclick="updateChart()">Update</button>
<canvas id="myChart"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var chartData = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: createDataset()
}
};
var chart = new Chart(ctx, chartData);
function updateChart(){
chartData.data.datasets = createDataset()
chart.update();
}
function createDataset(){
return [{
label: "My First dataset",
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: [0, 10, 5, 2, 20, 30, 45],
fill: false
}];
}
//ignore next line, it's to deal with a bug from chartjs cdn on stackoverflow
console.clear();
</script>
Related
I've implemented the technique described in this question to render vertical lines on my chart to show key dates when something important happened.
However, the text describing these events can be quite long, so just drawing text on the canvas isn't a good solution.
Is there some way to use the chart.js API to draw an invisible point on the chart (at the top of the line) which will become interactive and show a tooltip when the mouse hovers over it?
As far as I can see, only data points will show tooltips. I attempted to add another series to contain the lines data, but without much success - it also created a legend for this series, which I don't want. I set the values to 9999 to try to get them to appear at the top of the canvas, but this did not work and seems like a hack.
You could add a second dataset that contains a single value at the x-position where the vertical line should be drawn, its value should correspond to the highest value of the first dataset. To make the point invisible, define transparent background and border colors using 'rgba(0,0,0,0)'.
{
data: [null, null, 12],
pointRadius: 10,
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'rgba(0,0,0,0)'
}
To only display the legend label of the relevant dataset, you need to define a legend.labels.filter function.
legend: {
labels: {
filter: legendItem => legendItem.datasetIndex == 0
}
},
Further we need to define some tooltip.callback functions to show desired data in the tooltips.
Please take a look at below runnable code snippet and see how it works. This code uses the latest stable version of Chart.js (currently 2.9.3).
new Chart('canvas', {
type: 'line',
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
ctx.save();
var lineAtIndex = chart.data.datasets[0].lineAtIndex;
var x = xAxis.getPixelForTick(lineAtIndex);
ctx.strokeStyle = '#ff0000';
ctx.beginPath();
ctx.moveTo(x, yAxis.bottom);
ctx.lineTo(x, yAxis.top);
ctx.stroke();
ctx.restore();
}
}],
data: {
labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
datasets: [{
label: 'My Dataset',
data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1],
lineAtIndex: 2,
lineTooltip: ['This is', 'a multi-line', 'tooltip']
},
{
data: [null, null, 12],
pointRadius: 10,
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'rgba(0,0,0,0)'
}
]
},
options: {
legend: {
labels: {
filter: legendItem => legendItem.datasetIndex == 0
}
},
tooltips: {
callbacks: {
title: (tooltipItems, data) => {
if (tooltipItems[0].datasetIndex == 0) {
return data.labels[tooltipItems[0].index];
}
return data.datasets[0].lineTooltip;
},
label: (tooltipItems, data) => {
if (tooltipItems.datasetIndex == 0) {
return data.datasets[0].label + ': ' + data.datasets[0].data[tooltipItems.index];
}
return null;
}
}
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="canvas" height="90"></canvas>
Apart from the documentation I read (usually not helpful), I found some chart examples I want to implement to my page, but it seems not working. I tried to tweak it around but every time it gets load, it always displaying blank on the page.
Here's the code:
<div data-ng-controller="LineCtrl as line">
<canvas> data-sys-chart-line
data-dataset="line.data"
width="400"
height="240"></canvas>
</div>
<script type="text/javascript">
(function () {
'use strict';
function LineCtrl ( ) {
this.data = {
labels: ["January", "February", "March", "April", "May", "June"],
datasets: [
{
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
data: [40, 10, 60, 70, 20, 20]
},
{
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
data: [30, 70, 40, 90, 60, 70]
}
]
};
}
})();
</script>
<!-- Includes Dependencies here: AngularJS & Chart.js -->
<script src="script/Chart.js"></script>
<script src="script/angular-chart.min.js"></script>
<script src="script/tc-angular-chartjs.min.js"></script>
<script>
I included those .js files under /script folder in my project folder.
i have never used Chart.js before but seems that u are doing it wrong
you have never initialize the chart, by reading the documentation like for 10 second i found that you have to initialize it like this
var ctx = document.getElementById("here_is_the_canvas_element").getContext('2d');
var myChart = new Chart(ctx, { ... })
and you are using Chart.js code before you include the library
I've been working with ChartJS for the last couple of weeks and I'm getting used to it, however, I'm trying to add individual labels to my bars in my barchart and I can't figure it out.
Below is the code I'm using.
var config = {
type : 'bar',
data : {
datasets : [ {
label: numberOfFailures, //This line is the problem
data : failureData,
backgroundColor : colours,
} ],
labels : labels
},
options : {
responsive : true,
legend : {
position : 'bottom'
}
}
};
If I change the word label to labels they don't show up at all, but when it says label they all show up together. What I want is for array element 1 to appear on bar 1, etc.
If your aim is to take the values from an array and have them appear along the bottom of the bar chart so that each array value is the label for a bar then you need to set the data.labels value, not the data.datasets.label value.
For example, this basic chart is taken from the Chart.js documentation for bar chart data structure and shows how to use an array of month names to label the bars. Notice that the label bars go into the data.labels node.
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: [65, 59, 80, 81, 56, 55, 40],
}
]
};
If you programmatically create an array with one label for each point of data then it might look something like this:
var chartConfig = {};
for (score = 0; score < maxScore; ++score) {
chartConfig.scoreLabels[score] = score;
chartConfig.scoreData[score] = howManyAchievedScore(score);
}
var data = {
labels: chartConfig.scoreLabels,
datasets: [
{
label: "Number of players who achieved score",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: chartConfig.scoreData,
}
]
};
You don't have to create the labels and data values inside a single object, but it's usually tidier if you can group your chart configuration data into one object so that you can pass it from one function to another with one parameter.
The data.datasets.label value does something different, providing text which appears in the chart legend and in tooltips which appear when you hover over a bar.
I've been reading the docs, and there are ways to replace the data then update the chart:
myLineChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
myLineChart.update(); // Calling update now animates the position of March from 90 to 50.
https://github.com/chartjs/Chart.js/blob/master/docs/07-Advanced.md
But addData() appears to be gone, am I stuck with making my own addData for local data and then updating the whole chart? or am I missing something.
The update() handles adding data too. Just push your new data / labels into the config object that you passed when creating the chart and then call update()
For instance,
var config = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
data: [65, 0, 80, 81, 56, 85, 40],
fill: false
}]
}
};
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, config);
setTimeout(function(){
config.data.labels.push('Test');
config.data.datasets[0].data.push(3);
myChart.update();
}, 1000);
Fiddle - http://jsfiddle.net/zpnx8ppb/
I have the following AngularJS App:
angular.module("app-machines", ['ngFlatDatepicker'])
.factory('MachinesService', ['$http', MachinesService])
.controller('mainController', ['$scope', 'MachinesService', '$timeout', mainController])
.directive('onFinishRender', function ($timeout)
{
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
});
}
}
}
});
Where here is what happens (pasting code would be too long).
User has two controls (date from and date to) on a page, which upon changing fire an event which downloads data from a website (json).
Afterwards I am simply storing the returned json into an object $scope.machines.
Then I wait for ng-repeat on my webpage to finish rendering components (in my case for every item under ng-repeat I am creating a canvas where chart would be stored like following)
<div class="col-md-12" ng-repeat="machine in machines" on-finish-render="ngRepeatFinished">
<h1> {{ machine.name }}</h1>
<canvas id="{{'myChart_' + $index}}" width="400" height="400"></canvas>
</div>
Once this has finished rendering, I am calling the following function
$scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
//you also get the actual event object
//do stuff, execute functions -- whatever...
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
// The properties below allow an array to be specified to change the value of the item at the given index
// String or array - the bar color
backgroundColor: "rgba(100,220,220,0.2)",
// String or array - bar stroke color
borderColor: "rgba(220,220,220,1)",
// Number or array - bar border width
borderWidth: 1,
// String or array - fill color when hovered
hoverBackgroundColor: "rgba(220,220,220,0.2)",
// String or array - border color when hovered
hoverBorderColor: "rgba(220,220,220,1)",
// The actual data
data: [65, 59, 80, 81, 56, 55, 40],
// String - If specified, binds the dataset to a certain y-axis. If not specified, the first y-axis is used.
yAxisID: "y-axis-0",
},
{
label: "My Second dataset",
backgroundColor: "rgba(220,220,220,0.2)",
borderColor: "rgba(220,220,220,1)",
borderWidth: 1,
hoverBackgroundColor: "rgba(220,220,220,0.2)",
hoverBorderColor: "rgba(220,220,220,1)",
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
var options = {
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
};
for (var i = $scope.machines.length - 1; i >=0; i--) {
var ctx = $("#myChart_" + i);
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: options
});
myBarChart.update();
console.log("processed " + i);
}
});
Here is the problem that occurs. The page is generated, I can see all my canvas with the charts, however the bars are only displayed for one chart only. The bars on the remaining charts have for unknown reason hidden bar. However I can still hover over them like this:
FINAL
So in the end the problem was caused by the fact, that all my charts were bound to the same data source (I had a static data source for now). Once I changed it to dynamic data source (all charts had their own dataset) it suddenly worked like a charm.
What am I doing wrong here?