How can I implement Polar area charts with Chart.js and Canvas - javascript

Now,I would like to implement a polar area chart like following picture with Chart.js and Canvas.
How should I do to implement it?
So far,I tried the following code but it does not work.
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<style media="screen" type="text/css">#container{width:100%;height:100%;top:0;left:0;right:0;bottom:0;position:absolute;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
const canvas = document.getElementById('chart')
const ctx = canvas.getContext('2d');
const gradient = ctx.createRadialGradient(75, 50, 5, 90, 60, 100)
const [ w , h ] = [ canvas.clientWidth , canvas.clientHeight ];
gradient.addColorStop(0.0 , 'rgb(255,0,0)');
gradient.addColorStop(0.5 , 'rgb(0,255,0)');
const data = {
backgroundColor: [gradient,gradient,gradient,gradient,gradient],
labels: ['First label', 'Second label', 'Third label', 'Fourth label', 'Fifth label'],
datasets: [
{
label: 'First dataset',
backgroundColor: gradient,
data: [50, 20, 40, 50, 22]
}
]
};
const options = {
tooltips: {
mode: 'label'
},
};
const myRadarChart = new Chart(ctx, {
type: 'polarArea',
data,
options
});
});
</script>
</head>
<body>
<canvas id="chart" width="${width}" height="${width}" />
</body>
</html>

Try like this:
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<style media="screen" type="text/css">#container{width:100%;height:100%;top:0;left:0;right:0;bottom:0;position:absolute;}</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
const canvas = document.getElementById('chart')
const ctx = canvas.getContext('2d');
const [ w , h ] = [ canvas.clientWidth , canvas.clientHeight ];
const r = 300;
const gradient = ctx.createRadialGradient(w, h*1.2, 0, w, h, r * 0.6);
gradient.addColorStop(0.0 , 'rgb(255,0,0)');
gradient.addColorStop(1 , 'rgb(0,255,0)');
const data = {
backgroundColor: [gradient,gradient,gradient,gradient,gradient],
labels: ['First label', 'Second label', 'Third label', 'Fourth label', 'Fifth label'],
datasets: [
{
label: 'First dataset',
backgroundColor: gradient,
data: [50, 20, 40, 50, 22]
}
]
};
const options = {
tooltips: {
mode: 'label'
},
};
const myRadarChart = new Chart(ctx, {
type: 'polarArea',
data,
options
});
});
</script>
</head>
<body>
<canvas id="chart" width="${width}" height="${width}" />
</body>
</html>
The code is good! It's only a case of using the canvas width, height and radius of the chart's largest circle to position the gradient correctly. Minor adjustments can also be made if the final chart position in the canvas shifts (e.g. where a different canvas aspect ratio is used).
From there, it is simple to create a new gradient in the same way for each combination of colours you wish to use.

Related

How to change chart's backgroundColor for specific dataset with onclick event using ChartJS

// Set Chart Global Variables
let x_values = [0];
let y_values = [0];
let new_number = 0;
let index = 0;
// Intialize The Chart Canvas
let ctx = document.getElementById('chart_canvas').getContext('2d');
// Create New Line Chart
my_chart = new Chart(ctx, {
type: "line",
data: {
labels: [x_values[0]],
datasets: [{
backgroundColor: [],
fill: true,
pointStyle: "circle",
label: "Values",
data: [y_values[0]]
}]
}
});
// ------ Local Functions ------
function add() {
index = x_values.length;
new_number += 10;
my_chart.data.labels.push(index);
x_values.push(index);
my_chart.data.datasets.forEach((dataset) => {
dataset.data.push(new_number);
//The line below might be wrong since it is not changing the background color.
dataset.backgroundColor.push("#88c0d080");
});
my_chart.update();
}
function subtract() {
index = x_values.length;
new_number -= 10;
my_chart.data.labels.push(index);
x_values.push(index);
my_chart.data.datasets.forEach((dataset) => {
dataset.data.push(new_number);
//This line below might be wrong since it is not changing the background color.
dataset.backgroundColor.push("#bf616a80");
});
my_chart.update();
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testing Chart.js Line Chart</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.min.js" integrity="sha512-sW/w8s4RWTdFFSduOTGtk4isV1+190E/GghVffMA9XczdJ2MDzSzLEubKAs5h0wzgSJOQTRYyaz73L3d6RtJSg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<button type="button" onclick="add()" id="btnAdd">Add 10</button>
<button type="button" onclick="subtract()" id="btnSubtract">Subtract 10</button>
<canvas id="chart_canvas">Your browser does not support the HTML5 canvas tag.</canvas>
</body>
</html>
Expected Behavior:
When the "Add 10" button is clicked, a new point entry needs to be added with a backgroundColor fill
color of teal (#88c0d080).
When the "subtract 10" button is clicked, a new point entry needs to be added with a backgroundColor fill color of red (#bf616a80).
Current Behavior:
Only the point background color is being changed rather than the backgroundColor fill color.
Your help will be much appreciated.
You can use segment styling that update dynamicly when you add new data:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'orange',
fill: true,
segment: {
backgroundColor: (ctx) => (ctx.p0.parsed.y > ctx.p1.parsed.y ? 'red' : 'teal')
}
}]
},
options: {}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
const c = new Chart(ctx, options);
document.getElementById('add').addEventListener('click', () => {
c.data.labels.push(c.data.labels.length);
c.data.datasets[0].data.push(c.data.datasets[0].data[c.data.datasets[0].data.length - 1] + 10)
c.update()
});
document.getElementById('subb').addEventListener('click', () => {
c.data.labels.push(c.data.labels.length);
c.data.datasets[0].data.push(c.data.datasets[0].data[c.data.datasets[0].data.length - 1] - 10)
c.update()
});
<body>
<button id="add">
Add 10
</button>
<button id="subb">
Subtract 10
</button>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.js"></script>
</body>

Multiple charts in one page - Chartjs

I tried to add multiple charts in one page, but had the error Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused.
After research, I read that I had to set my canvas in div because :
Detecting when the canvas size changes can not be done directly from the CANVAS element. Chart.js uses its parent container to update the canvas render and display sizes. However, this method requires the container to be relatively positioned and dedicated to the chart canvas only. Responsiveness can then be achieved by setting relative values for the container size
So I did, but I still have the same error.
//chart1
const ctx = document.getElementById('chart1').getContext('2d')
const data1 = {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
}]
}
const options1 = {
scales: {
y: {
beginAtZero: true
}
}
}
const myChart1 = new Chart(ctx, {
type: 'doughnut',
data: data1,
options: options1
})
//chart2
const ctx2 = document.getElementById('chart2').getContext('2d')
const data2 = {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
}]
}
const options2 = {
scales: {
y: {
beginAtZero: true
}
}
}
const myChart2 = new Chart(ctx, {
type: 'line',
data: data2,
options: options2
})
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GraphJS</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js" integrity="sha512-QSkVNOCYLtj73J4hbmVoOV6KVZuMluZlioC+trLpewV8qMjsWqlIQvkn1KGX2StWvPMdWGBqim1xlC8krl1EKQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<div style="width: 400px; height: 400px; margin: 0 auto 100px auto;">
<h1 style="text-align: center;">Tier 1</h1>
<canvas id="chart1"></canvas>
</div>
<div style="width: 400px; height: 400px; margin: 0 auto 100px auto;">
<h1 style="text-align: center;">Category</h1>
<canvas id="chart2"></canvas>
</div>
<script src="./index.js"></script>
</body>
</html>
Any idea where is my mistake ?
You are passing ctx as a parameter for chart2, which should be ctx2. Right now both of your graphs are pointing to same document element i.e. to element with id chart1.
const myChart2 = new Chart(ctx2, {
type: 'line',
data: data2,
options: options2
})
Just do this

How to use ChartjsPluginStacked100 javascript only, no typescript

good day. Im trying to use the plugin chartjs-plugin-stacked100 with chart.js vs3 but im not having any luck. it stays as normal stacked horizontal bar chart.
I think im doing something wrong when importing or registering i but not know what im doing wrong.
here is how im doing my html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.0.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-stacked100#1.0.0"></script>
</head>
<body>
<div id="my-chart-container" style="height:400px;">
<canvas id="my-chart" ></canvas>
</div>
<script src="./index.js" type="module"></script>
</body>
</html>
and here is how im doing my js:
Chart.register(ChartjsPluginStacked100);
new Chart(document.getElementById("my-chart"), {
type: "bar",
data: {
labels: ["2010-2015", "2016", "2017", "2018", "2019"],
datasets: [
{ label: "IG", data: [0, 250, 7417.5, 650, 1455], backgroundColor: "rgba(244, 143, 177, 0.6)" },
{ label: "HY", data: [0, 0, 0, 1000, 0], backgroundColor: "rgba(255, 235, 59, 0.6)" },
{ label: "NR", data: [0, 675, 4182.5, 1505, 1735], backgroundColor: "rgba(100, 181, 246, 0.6)" }
]
},
options: {
indexAxis: 'y',
scales: {
xAxis:{
stacked:true
},
yAxis:{
stacked:true
},
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const datasetIndex = tooltipItem.datasetIndex;
const datasetLabel = data.datasets[datasetIndex].label;
// You can use two type values.
// `data.originalData` is raw values,
// `data.calculatedData` is percentage values, e.g. 20.5 (The total value is 100.0)
const originalValue = data.originalData[datasetIndex][tooltipItem.index];
const rateValue = data.calculatedData[datasetIndex][tooltipItem.index];
return `${datasetLabel}: ${rateValue}% (raw ${originalValue})`;
}
}
},
plugins: {
plugins:[ChartDataLabels],
stacked100: { enable: true, replaceTooltipLabel: false }
}
}
});
if anyone can guide me to do it correctly would be appreciated.
here is a jsbin with it, example
Thanks for your time.

How to set the xAxes min and max values of time cartesian chart in Chart.js

I want to create a diagram with Chart.js where the x-Axes is the time.
I want the diagram to show a entire day (from 0 a.m. to 24 p.m.).
Since my data doesn't start at 0 a.m. and doesn't end at 24 p.m. I wanted to set a min and max value for the axes. I tried some varietions but nothing really worked.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="my-chart.js"></script>
</body>
</html>
my-chart.js:
// setup block
const data = {
datasets: [{
label: 'Sales',
data: [
{x: '2021-08-08T13:12:23', y:3},
{x: '2021-08-08T13:12:45', y:5},
{x: '2021-08-08T13:12:46', y:6},
{x: '2021-08-08T13:13:11', y:3},
{x: '2021-08-08T13:14:23', y:9},
{x: '2021-08-08T13:16:45', y:1}
],
borderColor: 'rgba(234,124,234,0.4)',
backgroundColor: 'rgba(34,14,24,0.4)'
}]
};
// config block
const config = {
type: 'line',
data,
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'second'
}
},
y: {
beginAtZero: true
},
xAxes: [{
type: "time",
time: {
min: 1628373600,
max: 1628460000
}
}]
}
}
};
// render / init block
const myChart = new Chart(
document.getElementById('myChart'),
config
);
Is there a mistake in my code or why it isn't changing anything?
You are trying to use v2 and v3 config at the same time, this wont work. You need to remove the array format and only use the objects to define scales.
When placing the min and max props at the root of the x object for the x scale it works fine, although the time between the min and max you are using is only 1,5 minute:
// setup block
const data = {
datasets: [{
label: 'Sales',
data: [{
x: '2021-08-08T13:12:23',
y: 3
},
{
x: '2021-08-08T13:12:45',
y: 5
},
{
x: '2021-08-08T13:12:46',
y: 6
},
{
x: '2021-08-08T13:13:11',
y: 3
},
{
x: '2021-08-08T13:14:23',
y: 9
},
{
x: '2021-08-08T13:16:45',
y: 1
}
],
borderColor: 'rgba(234,124,234,0.4)',
backgroundColor: 'rgba(34,14,24,0.4)'
}]
};
// config block
const config = {
type: 'line',
data,
options: {
scales: {
x: {
type: 'time',
time: {
unit: 'second'
},
min: '2021-08-08T00:00:00',
max: '2021-08-08T23:59:59'
},
y: {
beginAtZero: true
}
}
}
};
// render / init block
const myChart = new Chart(
document.getElementById('myChart'),
config
);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="chart-container">
<canvas id="myChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="my-chart.js"></script>
</body>
</html>

Display Labels with Charts.JS

I created a radar chart with chart.js, however, I am having issues displaying the real data of my data points. I used the chart.js label plugin but it is displaying the point where the data point has plotted. How would I get it so my real data along with the label be displayed instead of the point where it is plotted. Many thanks!
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Apples</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/main.css">
<meta name="theme-color" content="#fafafa">
<script src="js/vendor/modernizr-3.8.0.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-3.4.1.min.js"><\/script>')</script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
</head>
<body>
<center><h3>Apple Values</h3></center>
<canvas id="Apple"></canvas>
<script>
var ctx = document.getElementById('Apple');
var real_data = [
['133', '425', '222', '621', '151'],
];
var data = {
labels: ['X', 'Y','Z','N','A'],
datasets: [{
label: 'Apples',
data: [.41, .5, .33, .72, .64],
backgroundColor: 'rgba(101,81,255,0.2)',
borderColor: 'rgba(101,81,255,0.5)',
borderWidth: 1,
pointBackgroundColor: 'rgba(0, 0, 0, 0.4)'
}]
};
var options = {
tooltips: {
callbacks: {
title: function(t, d) {
let title = d.datasets[t[0].datasetIndex].label;
return title;
},
label: function(t, d) {
let title = d.datasets[t.datasetIndex].label;
let label = d.labels[t.index];
let value = (title != 'Average') ? real_data[t.datasetIndex][t.index] : d.datasets[t.datasetIndex].data[t.index];
return label + ': ' + value;
}
}
}
};
var chart = new Chart(ctx, {
type: 'radar',
data: data,
options: options
});
</script>
</body>
</html>
you can either use plugins to change the chart after it is drawn or controllers to change how the chart is drawn since there is no direct way to manipulate rendering of charts. These are the links:
https://www.chartjs.org/docs/latest/developers/plugins.html
https://www.chartjs.org/docs/latest/developers/charts.html#extending-existing-chart-types
For your particular example, here is the code for using plugins, the easier of the two;
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Apples</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/main.css">
<meta name="theme-color" content="#fafafa">
<script src="js/vendor/modernizr-3.8.0.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-3.4.1.min.js"><\/script>')</script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.7.0"></script>
</head>
<body>
<center><h3>Apple Values</h3></center>
<canvas id="Apple"></canvas>
<script>
var ctx = document.getElementById('Apple');
var real_data = [
['133', '425', '222', '621', '151'],
];
var data = {
labels: ['X', 'Y','Z','N','A'],
datasets: [{
label: 'Apples',
data: [.41, .5, .33, .72, .64],
backgroundColor: 'rgba(101,81,255,0.2)',
borderColor: 'rgba(101,81,255,0.5)',
borderWidth: 1,
pointBackgroundColor: 'rgba(0, 0, 0, 0.4)'
}]
};
var options = {
tooltips: {
callbacks: {
title: function(t, d) {
let title = d.datasets[t[0].datasetIndex].label;
return title;
},
label: function(t, d) {
let title = d.datasets[t.datasetIndex].label;
let label = d.labels[t.index];
let value = (title != 'Average') ? real_data[t.datasetIndex][t.index] : d.datasets[t.datasetIndex].data[t.index];
return label + ': ' + value;
}
}
}
};
var plugins = [{
afterDatasetsDraw: function(chart) {
var real_data = ['133', '425', '222', '621', '151'];
var ctx = chart.ctx;
chart.data.datasets.forEach(function(dataset, index) {
var datasetMeta = chart.getDatasetMeta(index);
if (datasetMeta.hidden) return;
datasetMeta.data.forEach(function(point, index) {
var value = real_data[index],
x = point.getCenterPoint().x,
y = point.getCenterPoint().y,
radius = point._model.radius,
fontSize = 14,
fontFamily = 'Verdana',
fontColor = 'black',
fontStyle = 'normal';
ctx.save();
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.font = fontStyle + ' ' + fontSize + 'px' + ' ' + fontFamily;
ctx.fillStyle = fontColor;
ctx.fillText(value, x, y - radius - fontSize);
ctx.restore();
});
});
}
}]
var chart = new Chart(ctx, {
type: 'radar',
data: data,
options: options,
plugins: plugins
});
</script>
</body>
</html>

Categories