Chart.js Mouse Over Show Old Chart Data - javascript

I was having some problem when trying to redraw chart on canvas using chart.js in Angular. Here is my HTML component:
<div class="form-group">
<select [(ngModel)]="timeMode" id="timeModeInput" class="browser-default custom-select" (change)="onTimeModeChange($event)">
<option value="all" selected>Yearly</option>
<option value="monthly">Monthly</option>
</select>
</div>
<canvas id="expenseTimelineCanvas"></canvas>
Upon dropdown select, I repopulate the chart:
if (chart != null) { chart.destroy(); chart.clear(); }
chart = new Chart(chartName, {
type: "line",
data: {
labels: labels,
datasets: [
{
data: chartData,
borderColor: lineColor,
fill: false,
borderWidth: 1,
borderDash: [10, 10],
pointBackgroundColor: "white",
pointBorderColor: lineColor,
pointRadius: 5
}
]
}
}
});
However, when I mouse over at certain part of the canvas, the old chart will be displayed. Any ideas on how to totally destroy the canvas before replotting on the same DOM element?
Thanks!

this happens because chartjs uses canvas and for redrawing you just have to destroy old drawing from the canvas.
when you make a new chart then you have to destroy the old chart.
but in angular you can also just reload the component to destroy the chart
your method
//this method
initChart(){
//this will generate chart you need
//before generating just destroy the old chart
}
second method
//in html file
<thisIsHTMLTagOfChartComponent *ngIf="showChart">
</thisIsHTMLTagOfChartComponent>
//in typescript
public showChart = false;
//this function will be called everytime you fetch the data from server
getChartData(){
this.showChart = false; //this will remove the component from the page
fetchData(uri)
.then(result => {
//do your stuff here
this.showChart = true // this will load the component in the page again
}
)

i prefer to not destroy your chart just change the value of it for e.g: in your change function just load a new chart definition in your same chart with new config, we have 2 different configs:
config = {
type: 'bar',
data: {
labels: dringlichkeiten.map(x => x.id),
datasets: [
{
label: 'My Bar Chart',
data: dringlichkeiten.map(x => x.value),
backgroundColor: ['red', 'green', 'yellow', 'blue', 'orange']
}
]
},
}
config2 = {
type: 'line',
data: {
datasets: [{
label: 'Höhenlinie',
backgroundColor: "rgba(255, 99, 132,0.4)",
borderColor: "rgb(255, 99, 132)",
fill: true,
data: [
{ x: 1, y: 2 },
{ x: 2500, y: 2.5 },
{ x: 3000, y: 5 },
{ x: 3400, y: 4.75 },
{ x: 3600, y: 4.75 },
{ x: 5200, y: 6 },
{ x: 6000, y: 9 },
{ x: 7100, y: 6 },
],
}]
},
options: {
responsive: true,
title: {
display: true,
text: 'Höhenlinie'
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
ticks: {
userCallback: function (tick) {
if (tick >= 1000) {
return (tick / 1000).toString() + 'km';
}
return tick.toString() + 'm';
}
},
scaleLabel: {
labelString: 'Länge',
display: true,
}
}],
yAxes: [{
type: 'linear',
ticks: {
userCallback: function (tick) {
return tick.toString() + 'm';
}
},
scaleLabel: {
labelString: 'Höhe',
display: true
}
}]
}
}
}
chart: Chart ;
in your change function just load a new config:
change(){
this.chart = new Chart('canvas', this.config2)
}
DEMO.

Related

Chart.js Scatter Chart bounds: 'data' Issue

I'm currently struggling with building a web frontend with a responsive chart, which should be filled with live data while the user is visiting the application.
My goal was to have the x-axis always scale automatically to perfectly cover the data. Then I found the bounds attribute of Chart.js, which when set to 'data' should do exactly what I want.
As you can see in this example, the whole thing only works well for the first few datasets - from x-values > 5 onwards, the scaling of the x-axis somehow gets messed up.
Did anyone else have this problem before? Did I assign other attributes incorrectly?
Here's my JavaScript code:
var data = [];
var graph = new Chart("chart", {
type: 'scatter',
data: {
datasets: [{
data: data,
pointRadius: 0,
borderWidth: 2,
pointHitRadius: 4,
pointHoverRadius: 6,
tension: 0,
showLine: true,
xAxisID: "xAxis",
yAxisID: "yAxis",
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: false,
plugins: {
legend: {
display: false,
},
},
interaction: {
mode: 'nearest',
intersect: true,
},
scales: {
xAxis: {
type: 'linear',
position: 'bottom',
title: {
display: true,
text: 't (s)',
color: "black",
font: {
size: 15
}
},
ticks: {
color: "black",
callback: (value, index, values) => (index == (values.length - 1)) ? "" : value,
},
bounds: 'data'
},
yAxis: {
type: 'linear',
position: 'left',
ticks: {
color: "black",
maxTicksLimit: 7,
}
}
}
}
});
var x = 0;
setInterval(function() {
var newData = {
x: Math.round(x * 100) / 100,
y: Math.round(x * 100) / 100
};
data.push(newData);
graph.update();
x += 0.1;
}, 100);

Style individual points from one dataset in Chart.js

I am trying to create a timeline using Chart.js.
My Goal is to have a single row that shows various icons/events that happened in a game.
By using a linechart and removing the lines, leaving only the points, you can place markers on the timeline.
You can display these points as custom images by assigning an image variable to the pointStyle attribute of the dataset.
With a single image this works perfectly fine, as you can see in the following snippet.
//Create the image
const img = new Image(20,20);
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Skull_Icon_%28Noun_Project%29.svg/1200px-Skull_Icon_%28Noun_Project%29.svg.png";
var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: "Deaths",
data: [{x:"00:01:23", y: 0},{x:"00:03:41", y: 0},{x:"00:04:29", y: 0},{x:"00:05:35", y: 0},{x:"00:06:27", y: 0},{x:"00:07:07", y: 0},{x:"00:08:48", y: 0},{x:"00:09:31", y: 0}],
//Assign the image in the point Style attribute
pointStyle:img,
showLine: false,
fill: false,
tooltip: "Player Died",
borderColor: "#000000",
backgroundColor: "#000000"
},
]},
//The Rest is just styling
options: {
interaction:{
mode:'nearest'
},
tooltips:{
custom: function(tooltip){
if(!tooltip)return;
tooltip.displayColors = false;
},
callbacks:{
title: function(tooltipItem, data) {
return data.datasets[tooltipItem[0].datasetIndex]['tooltip'];
},
label: function(tooltipItem, data) {
return tooltipItem.xLabel;
}
}
},
legend: {
display: true
},
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'hh:mm:ss',
tooltipFormat: 'HH:mm:ss',
displayFormats: {
second: "HH:mm:ss"
},
unitStepSize: 30
},
ticks:{
fontColor: "white"
}
}],
yAxes: [{
ticks: {
display: false,
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<canvas id="chart" height= "50px" style="background-color: rgb(200, 200, 200);"></canvas>
As you can see i am creating an Image(), pointing it to the source and assigning it as the pointStyle attribute of the dataset.
But with this method i need to create a new Dataset whenever i want to display another image.
For my purpose i need to be able to dynamically assign different images for every point.
That is why i looked into scriptables in Chart.js. On the documentation it is stated that you can use custom functions to return an image/styling for pointStyles.
https://www.chartjs.org/docs/latest/general/options.html
In the following snippet you can see my current code.
I moved the creation of the image to a custom function in the point Style attribute of the dataset. With this i will be able to select from more images later.
But for now i can not make it work with one image. So how can i make the function return an image, so that the styling works? With this i will later be able to select from multiple images. Or is there maybe another solution i did not come up with?
Thank you very much for your help.
var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: "Deaths",
data: [{x:"00:01:23", y: 0},{x:"00:03:41", y: 0},{x:"00:04:29", y: 0},{x:"00:05:35", y: 0},{x:"00:06:27", y: 0},{x:"00:07:07", y: 0},{x:"00:08:48", y: 0},{x:"00:09:31", y: 0}],
//Try to create the image in a custom function
pointStyle: function(context){
var img = new Image(20,20);
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Skull_Icon_%28Noun_Project%29.svg/1200px-Skull_Icon_%28Noun_Project%29.svg.png";
return img;
},
showLine: false,
fill: false,
tooltip: "Player Died",
borderColor: "#000000",
backgroundColor: "#000000"
},
]},
options: {
interaction:{
mode:'nearest'
},
tooltips:{
custom: function(tooltip){
if(!tooltip)return;
tooltip.displayColors = false;
},
callbacks:{
title: function(tooltipItem, data) {
return data.datasets[tooltipItem[0].datasetIndex]['tooltip'];
},
label: function(tooltipItem, data) {
return tooltipItem.xLabel;
}
}
},
legend: {
display: true
},
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'hh:mm:ss',
tooltipFormat: 'HH:mm:ss',
displayFormats: {
second: "HH:mm:ss"
},
unitStepSize: 30
},
ticks:{
fontColor: "white"
}
}],
yAxes: [{
ticks: {
display: false,
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<canvas id="chart" height= "50px" style="background-color: rgb(200, 200, 200);"></canvas>
You can add different images via an array.
//Create the image
const img = new Image(20, 20);
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Skull_Icon_%28Noun_Project%29.svg/1200px-Skull_Icon_%28Noun_Project%29.svg.png";
const img2 = new Image(20, 20);
img2.src = "https://pngimg.com/uploads/pacman/pacman_PNG21.png";
const img3 = new Image(20, 20);
img3.src = "https://pngimg.com/uploads/pacman/pacman_PNG70.png"
var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: "Deaths",
data: [{
x: "00:01:23",
y: 0
}, {
x: "00:03:41",
y: 0
}, {
x: "00:04:29",
y: 0
}, {
x: "00:05:35",
y: 0
}, {
x: "00:06:27",
y: 0
}, {
x: "00:07:07",
y: 0
}, {
x: "00:08:48",
y: 0
}, {
x: "00:09:31",
y: 0
}],
//Assign the image in the point Style attribute
pointStyle: [img2, img, img3],
showLine: false,
fill: false,
tooltip: "Player Died",
borderColor: "#000000",
backgroundColor: "#000000"
}, ]
},
//The Rest is just styling
options: {
interaction: {
mode: 'nearest'
},
tooltips: {
custom: function(tooltip) {
if (!tooltip) return;
tooltip.displayColors = false;
},
callbacks: {
title: function(tooltipItem, data) {
return data.datasets[tooltipItem[0].datasetIndex]['tooltip'];
},
label: function(tooltipItem, data) {
return tooltipItem.xLabel;
}
}
},
legend: {
display: true
},
scales: {
xAxes: [{
type: 'time',
time: {
parser: 'hh:mm:ss',
tooltipFormat: 'HH:mm:ss',
displayFormats: {
second: "HH:mm:ss"
},
unitStepSize: 30
},
ticks: {
fontColor: "white"
}
}],
yAxes: [{
ticks: {
display: false,
},
gridLines: {
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
<canvas id="chart" height="50px" style="background-color: rgb(200, 200, 200);"></canvas>
How you get the images to the array is up to you.
You can update it with something like this
function addimage(img) {
myChart.data.datasets[0].pointStyle.push(img);
myChart.update();
};
addimage(img2)
Of course you will want to add your images in some other dynamic way I’m sure but this should help.

How to set percentage value by default on each bars in horizontal bar chart js

I have used horizontal bar chart from chart.js where i need percentage values to be shown next to each bar at right side? here is the bar sample image.
click here to view sample image of bar chart
Also these are the options i have tried :
xAxes: [
{
ticks: {
min: 0,
max: 100
},
grid: {
offset: false
}
},
],
yAxes: [
{
gridLines: {
display: false,
},
display: "right",
barPercentage: 0.8,
minBarLength: 2,
},
],
Is there any option which can turn the percentage values on at he right side of the horizontal bar chart?
Please click below image to see the expected output
click image expected output
You can make use of the datalabels plugin
Example:
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.3.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0-rc"></script>
<canvas id="myChart" width="850" height="520"></canvas>
<script>
var ctx = document.getElementById('myChart');
Chart.register(ChartDataLabels);
Chart.defaults.set('plugins.datalabels', {
color: '#FE777B'
});
var myChart = new Chart(ctx, {
type: 'bar',
plugins: [ChartDataLabels],
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
data: [12, 19, 3, 5, 2, 3],
label: 'Advisor Closed MTD',
backgroundColor: 'rgb(192,111,94)',
barThickness: 25,
datalabels: {
color: '#FFCE56'
}
}],
},
options: {
indexAxis: 'y',
responsive: false,
plugins: {
datalabels: {
formatter: (val, context) => (`${val}%`),
anchor: 'end',
align: 'end',
labels: {
value: {
color: 'blue'
}
}
}
}
}
});
</script>

How to display final point value in charts.js

I'm using Charts.js library to display a line graph from data which is constantly updated. Is there a way to display only the final point value at all times? I want it to do this to monitor the added values at all times.
javascript code:
var config2 = {
type: 'line',
data: {
labels: 0,
datasets: [{
label: "No selection",
lineTension: 0,
borderColor: "rgba(222, 44, 31)",
pointBackgroundColor: "#fff675",
fill: false,
data: 0,
}
]
},
options: {
responsive: true,
title: {
display: false,
text: 'Chart.js Time Point Data'
},
scales: {
x: {
type: 'time',
display: true,
scaleLabel: {
display: true,
labelString: 'Date'
},
ticks: {
major: {
enabled: true
},
fontStyle: function(context) {
return context.tick && context.tick.major ? 'bold' : undefined;
},
fontColor: function(context) {
return context.tick && context.tick.major ? '#FF0000' : undefined;
}
}
},
y: {
display: true,
scaleLabel: {
display: true,
labelString: 'value'
}
}
}
}
};
Each time, a new value is available, you can simply remove outdated labels and dataset.data values once a certain limit is reached. This can be done using Array.shift(), which removes the first element from an array. Once these array are updated, you need to invoke chart.update().
var maxValues = 4;
setInterval(() => {
chart.data.labels.push(new Date());
chart.data.datasets[0].data.push(Math.floor((Math.random() * 20) + 1));
if (chart.data.labels.length > maxValues) {
chart.data.labels.shift();
chart.data.datasets[0].data.shift();
}
chart.update();
}, 1000);
For displaying the value on the last added data point, you can use the Plugin Core API. It offers different hooks that may be used for executing custom code. In below runnable code snippet, I use the afterDraw hook to draw text directly on the canvas.
var chart = new Chart('chart', {
type: "line",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
var iLastValue = chart.data.labels.length - 1;
var lastValue = chart.data.datasets[0].data[iLastValue];
var x = xAxis.getPixelForValue(chart.data.labels[iLastValue]);
var y = yAxis.getPixelForValue(lastValue);
ctx.save();
ctx.textAlign = 'center';
ctx.font = '14px Arial';
ctx.fillStyle = "red";
ctx.fillText('Value: ' + lastValue, x, y - 15);
ctx.restore();
}
}],
responsive: true,
maintainAspectRatio: false,
data: {
labels: [],
datasets: [{
label: "Data",
data: [],
fill: false,
lineTension: 0,
backgroundColor: "white",
borderColor: "red",
}]
},
options: {
layout: {
padding: {
right: 50
}
},
scales: {
xAxes: [{
type: 'time',
ticks: {
source: 'auto'
},
time: {
unit: 'second',
displayFormats: {
second: 'mm:ss'
},
tooltipFormat: 'mm:ss'
},
}],
yAxes: [{
ticks: {
min: 0,
max: 20,
stepSize: 5
}
}]
}
}
});
var maxValues = 4;
setInterval(() => {
chart.data.labels.push(new Date());
chart.data.datasets[0].data.push(Math.floor((Math.random() * 20) + 1));
if (chart.data.labels.length > maxValues) {
chart.data.labels.shift();
chart.data.datasets[0].data.shift();
}
chart.update();
}, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="chart" height="90"></canvas>

How to Remove axis Lines from chart in chart js

I drawn a chart using chart js like below
In this above chart i want to make a line thicker ( Pink Marked ) like other lines and also i want to remove x axis line ( Green Marked ). How can i do this please Help me.
Please see the fiddle Here Live Chart
var ganttchart = document.getElementById('bar-chart');
new Chart(ganttchart, {
type: 'line',
data: {
datasets: [
{
label: 'Scatter Dataset',
backgroundColor: "rgba(246,156,85,1)",
borderColor: "rgba(246,156,85,1)",
fill: false,
borderWidth : 15,
pointRadius : 0,
data: [
{
x: 0,
y: 9
}, {
x: 3,
y: 9
}
]
},
{
backgroundColor: "rgba(208,255,154,1)",
borderColor: "rgba(208,255,154,1)",
fill: false,
borderWidth : 15,
pointRadius : 0,
data: [
{
x: 3,
y: 7
}, {
x: 5,
y: 7
}
]
},
{
label: 'Scatter Dataset',
backgroundColor: "rgba(246,156,85,1)",
borderColor: "rgba(246,156,85,1)",
fill: false,
borderWidth : 15,
pointRadius : 0,
data: [
{
x: 5,
y: 5
}, {
x: 10,
y: 5
}
]
},
{
backgroundColor: "rgba(208,255,154,1)",
borderColor: "rgba(208,255,154,1)",
fill: false,
borderWidth : 15,
pointRadius : 0,
data: [
{
x: 10,
y: 3
}, {
x: 13,
y: 3
}
]
}
]
},
options: {
legend : {
display : false
},
scales: {
xAxes: [{
type: 'linear',
position: 'top',
gridLines: {
lineWidth:20
},
ticks : {
beginAtzero :true,
stepSize : 1
}
}],
yAxes : [{
gridLines: {
display:false,
},
ticks : {
beginAtZero :true,
max : 10,
display:false
}
}]
},
animation: {
duration: 0
},
hover: {animationDuration: 0}
}
});
You can find axes config options currently here: Axes - Chart.js Documentation
Axes config options has a global field display with the following description:
If set to false the axis is hidden from view. Overrides gridLines.display, scaleLabel.display, and ticks.display.
Here is how I have implemented it:
public chartOptions = {
scales: {
xAxes: [{
display: false,
}],
yAxes: [{
display: false,
}]
}
};
Just change border to false.
const config =
{
type: 'line',
data,
options: {
scales:{
y: {
beginAtZero: false,
border:{
display:false
}
},
x: {
beginAtZero: false,
border:{
display:false
}
}
}
}
}
}

Categories

Resources