Is there a way to have multiple colors?
Example:
Thank you!
New answer:
My original answer bothered me and I thought there must be a better way to achieve this style. So here's a much better solution that uses a radial gradient.
Note that this implementation is quite naïve in that it only supports a single dataset!
const colours = [
{ primary: '#fec1c6', shadow: '#e8b0b5' },
{ primary: '#bdeeed', shadow: '#aad2d0' },
{ primary: '#e4da84', shadow: '#d3ca76' }
];
new Chart(document.getElementById('chart'), {
type: 'doughnut',
data: {
datasets: [{
data: [3, 2, 2]
}]
},
options: {
cutoutPercentage: 65
},
plugins: [{
beforeDatasetsUpdate: c => {
const x = (c.chartArea.right + c.chartArea.left) / 2,
y = (c.chartArea.bottom + c.chartArea.top) / 2,
bgc = [];
for (let i = 0; i < colours.length; i++) {
const gradient = c.ctx.createRadialGradient(x, y, c.innerRadius, x, y, c.outerRadius);
gradient.addColorStop(0, colours[i].shadow);
gradient.addColorStop(.4, colours[i].shadow);
gradient.addColorStop(.45, colours[i].primary);
gradient.addColorStop(1, colours[i].primary);
bgc.push(gradient);
}
c.config.data.datasets[0].backgroundColor = bgc;
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="75"></canvas>
Original answer:
If you don't mind a 'dirty' solution you can achieve a similar visual result by duplicating your dataset, e.g.:
const values = [3, 2, 2],
primaryColours = ['#fec1c6', '#bdeeed', '#e4da84'],
secondaryColours = ['#e8b0b5', '#aad2d0', '#d3ca76'];
new Chart(document.getElementById('chart'), {
type: 'doughnut',
data: {
datasets: [{
data: values,
weight: 2,
backgroundColor: primaryColours,
borderColor: primaryColours
}, {
data: values,
weight: 1,
backgroundColor: secondaryColours,
borderColor: secondaryColours
}]
},
options: {
cutoutPercentage: 65
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="75"></canvas>
Related
I have few values like A and B now I have pair of them I am showing them on chart-js like this
Now for my use case, I am calculating the third value using A and B. E.g a=100 and b=50, and dividing them will give me c=2.0. Now I want to show this c value on top of A and B bar as a common label like this
"chart.js": "^3.3.0",
react-js
const newChartInstance = new Chart(chartContainer.current, {
type: "bar",
options: {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true,
},
},
],
},
...config.options,
onClick: (e) => {
const points = newChartInstance.getElementsAtEventForMode(
e,
"nearest",
{ intersect: true },
true
);
if (points.length) {
const firstPoint = points[0];
var type =
newChartInstance.data.datasets[firstPoint.datasetIndex].label;
var label = newChartInstance.data.labels[firstPoint.index];
var value =
newChartInstance.data.datasets[firstPoint.datasetIndex].data[
firstPoint.index
];
// This is the result that you will use to breakdown the chart
//console.log(label, value, type);
dispatch(setClickedBar({ label, value, type, tile: props.tile }));
}
},
},
data: data,
});
You can use a custom plugin for that:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
customValue: {
name: 'ROI',
}
}
},
plugins: [{
id: 'customValue',
afterDraw: (chart, args, opts) => {
const {
ctx,
data: {
datasets
},
_metasets
} = chart;
datasets[0].data.forEach((dp, i) => {
let barValue = `${(datasets[1].data[i] + dp) / 2}%`;
const lineHeight = ctx.measureText('M').width;
const textVal = opts.name || 'fill'
ctx.textAlign = 'center';
ctx.fillText(barValue, _metasets[0].data[i].x, (_metasets[0].data[i].y - lineHeight * 1.5), _metasets[0].data[i].width);
ctx.fillText(textVal, _metasets[0].data[i].x, (_metasets[0].data[i].y - lineHeight * 3), _metasets[0].data[i].width);
});
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.1/chart.js"></script>
</body>
I have a javascript map like this..
var Severity = {
3M:[0, 3, 1, 0, 0],
5T:[0, 0, 1, 0, 0],
6S:[0, 0, 2, 0, 0]
}
And a JS function to call Stacked Chart Bar. Here I have a created a JS function which takes id and a map from jsp page. Map structure is same as above defined. I want to display graph where in x axis the data is the keys in map and in y axes is the stacked up data of 5 elements.
function StackedBar(id,Severity) {
var label = Object.keys(Severity); // getting the labels
var Critical = [];
var High = [];
var Medium = [];
var Low = [];
var Others = [];
for(let i=0;i<label.length;i++){ //assigning the data to arrays created
Critical.push(Severity[label[i]][0]);
High.push(Severity[label[i]][1]);
Medium.push(Severity[label[i]][2]);
Low.push(Severity[label[i]][3]);
Others.push(Severity[label[i]][4]);
}
var ctxL = document.getElementById(id).getContext('2d'); //id from the html canvas
var chart = new Chart(ctxL, {
type: 'bar',
data: {
labels: label,
datasets: [
{
label: 'Critical',
data: Critical,
backgroundColor: '#aa000e'
},
{
label: 'High',
data: High,
backgroundColor: '#e65905'
},
{
label: 'Medium',
data: Medium,
backgroundColor: '#e00ce6'
},
{
label: 'Low',
data: Low,
backgroundColor: '#b8ab16'
},
{
label: 'Others',
data: Others,
backgroundColor: '#00aaaa'
}
]
},
options: {
responsive: true,
legend: {
position: 'right'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
});
}
Here graph displays and i get label in x axes...but graph values doesn't show and i get following error..
Html
<canvas id="overall"></canvas>
<script>StackedBar('overall',Overall);</script>
I wanted to know what went wrong and want me to help fix this issue...
I put the above together into one file and it works (although I had to change "Overall" to "Severity" in the call). So I'd expect that something you are using might not match your example above.
The version I used:
<html>
<body>
<canvas id="overall"></canvas>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script>
var Severity = {
"3M": [0, 3, 1, 0, 0],
"5T": [0, 0, 1, 0, 0],
"6S": [0, 0, 2, 0, 0]
};
</script>
<script>
function StackedBar(id, Severity) {
var label = Object.keys(Severity); // getting the labels
var Critical = [];
var High = [];
var Medium = [];
var Low = [];
var Others = [];
for (let i = 0; i < label.length; i++) { //assigning the data to arrays created
Critical.push(Severity[label[i]][0]);
High.push(Severity[label[i]][1]);
Medium.push(Severity[label[i]][2]);
Low.push(Severity[label[i]][3]);
Others.push(Severity[label[i]][4]);
}
var ctxL = document.getElementById(id).getContext('2d'); //id from the html canvas
var chart = new Chart(ctxL, {
type: 'bar',
data: {
labels: label,
datasets: [
{
label: 'Critical',
data: Critical,
backgroundColor: '#aa000e'
},
{
label: 'High',
data: High,
backgroundColor: '#e65905'
},
{
label: 'Medium',
data: Medium,
backgroundColor: '#e00ce6'
},
{
label: 'Low',
data: Low,
backgroundColor: '#b8ab16'
},
{
label: 'Others',
data: Others,
backgroundColor: '#00aaaa'
}
]
},
options: {
responsive: true,
legend: {
position: 'right'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
});
}
</script>
<script>StackedBar('overall', Severity);</script>
</html>
I'm trying to create a chart with a time axis in Vue using Chart.js. When I set the data right in the Data object like so, everything works correctly:
chartData: {
datasets: [
{
backgroundColor: '#ED645A',
borderColor: '#ED645A',
fill: false,
data: [
{
t: new Date("1998-1-1"),
y: 7.1
},
{
t: new Date("1998-2-1"),
y: 8.4
},
{
t: new Date("1998-3-1"),
y: 18.5
},
{
t: new Date("1998-4-1"),
y: 16.2
},
{
t: new Date("1998-5-1"),
y: 18.4
}
]
}
]
},
But when I'm trying to load the data from JSON and form the datasets object in computed property, like so, it doesn't work:
import pureSecondDatasetJson from "../assets/pureSecondDataset.json"
...
export default {
...
data () {
return {
pureSecondDataset: pureSecondDatasetJson,
charts: [
chartData: {
datasets: this.foo
},
...
computed: {
foo() {
var plotData = []
for (var i=0; i<this.pureSecondDataset.length; i++) {
plotData.push({t: new Date(this.pureSecondDataset[i].t), y: this.pureSecondDataset[i].y})
}
var chartData = [
{
backgroundColor: '#ED645A',
borderColor: '#ED645A',
fill: false,
data: plotData
}
];
return chartData
}
}
The object, created in computed seems the same as the one, which put directly, so why it doesn;t work?
You shouldn't try access a computed property from your data as explained on the Vue Forum.
the data is evaluated before the computed array
I would advise changing your computed property to something like below and then use that as your chart data:
foo() {
var plotData = []
for (var i=0; i<this.pureSecondDataset.length; i++)
plotData.push({t: new Date(this.pureSecondDataset[i].t), y: this.pureSecondDataset[i].y})
return {
chartData: {
datasets:[{
backgroundColor: '#ED645A',
borderColor: '#ED645A',
fill: false,
data: plotData
}]
}
}
}
I've added a fiddle to show how you can do this by not using the computed property in data. While I was making the fiddle I found that for a proper line graph you need to have a labels property for the x-values otherwise you can use type: scatter and drawLine:true to specify the x and y values together. Chart.js - Plot line graph with X , Y coordinates
new Vue({
el: "#app",
data: () => {
return {
plotData: [{
x: 1,
y: 1
}, {
x: 2,
y: 2
}, {
x: 3,
y: 3
}]
}
},
computed: {
foo() {
return {
type: 'scatter',
data: {
datasets: [{
showLine: true,
label: 'My First dataset',
backgroundColor: 'rgb(255, 99, 132)',
borderColor: 'rgb(255, 99, 132)',
data: this.plotData
}]
}
}
}
},
mounted() {
var ctx = document.getElementById('chart').getContext('2d');
new Chart(ctx, this.foo);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<div id="app">
<canvas id="chart" width="400" height="400"></canvas>
</div>
I am trying to replace points of a scatter plot with a PNG image. Based on the documentation, the pointStyle accepts either a string or an image. However instead of the image on the first point, it just shows a regular scatter plot point. Any ideas?
var ctx = document.getElementById("myChart").getContext('2d');
var img = new Image();
var img1 = img.src = 'assets/img/small/STORM.png';
var imageData = {
datasets: [{
pointStyle: [img1, 'rect', 'triangle', 'circle'],
data: [{
x: 1.447377,
y: -0.014573
}, {
x: 2.365398,
y: -1.062847
}, {
x: -2.507778,
y: 0.389309
}, {
x: -0.432636,
y: 0.124841
}]
}]
}
var myChart = new Chart(ctx, {
type: 'scatter',
data: imageData,
options: {}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
You can see a working example in jsfiddle here
According to Chart.js documentation, pointStyle is either a string or an Image but not an array.
If you want to have individual styles for your points, you can use the Plugin Core API. It offers several hooks that may be used for executing custom code. You could use the afterDraw hook to assign a different pointStyle to each point.
plugins: {
afterUpdate: function(chart) {
const meta = chart.getDatasetMeta(0);
meta.data[0]._model.pointStyle = img;
meta.data[1]._model.pointStyle = 'rect';
meta.data[2]._model.pointStyle = 'triangle';
meta.data[3]._model.pointStyle = 'circle';
}
},
I your amended code below, I used a slightly different but more compact approach and defined the pointStyles array outside of the chart configuration.
const img = new Image();
img.src = 'https://i.stack.imgur.com/gXQrT.png';
const pointStyles = [img, 'rect', 'triangle', 'circle'];
new Chart(document.getElementById('myChart'), {
type: 'scatter',
plugins: {
afterUpdate: chart => {
chart.getDatasetMeta(0).data.forEach((d, i) => d._model.pointStyle = pointStyles[i]);
}
},
data: {
datasets: [{
data: [
{x: 1.447377, y: -0.014573},
{x: 2.365398, y: -1.062847},
{x: -2.507778, y: 0.389309},
{x: -0.432636, y: 0.124841}
],
backgroundColor: ['white', 'green', 'red', 'orange'],
pointRadius: 10
}]
},
options: {
legend: {
display: false
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="90"></canvas>
Following is my javascript Code, but the only thing really relevant is the last function. I want to update the Chart to add another dataset, without reloading the Page. But for reason the added dataset is always undefined. The commented-out line, which uses the exact same array of data, on the other hand works. Since I'm new to javascript I'm not sure, if I missed something obvious, or if chart.js just doesn't support this kind of thing at all.
const CHART = document.getElementById("lineChart");
var dts1 = [
{
label: "Abfall gesamt",
data: Abfall_gesamt,
}
];
var dts2 = [
{
label: "Abfall schadstoffhaltiger",
data: Abfall_schadstoff,
}
];
var lineChart = new Chart(CHART, {
type: 'line',
data: {
labels: Jahr,
datasets: dts1
}
});
function myFunction(){
//lineChart.data.datasets[0].data = Abfall_schadstoff;
lineChart.data.datasets.push(dts2);
lineChart.update();
}
The issue is, you are defining your datasets (dts1 and dts2) as an array. They should be an object, like so ...
var dts1 = {
label: "Abfall gesamt",
data: Abfall_gesamt,
};
var dts2 = {
label: "Abfall schadstoffhaltiger",
data: Abfall_schadstoff,
};
and then, when generating the chart, set datasets value as ...
datasets: [dts1]
ᴅᴇᴍᴏ
const CHART = document.getElementById("lineChart");
var Abfall_gesamt = [1, 2, 3];
var Abfall_schadstoff = [4, 5, 6]
var dts1 = {
label: "Abfall gesamt",
data: Abfall_gesamt,
backgroundColor: 'rgba(255, 0, 0, 0.2)'
};
var dts2 = {
label: "Abfall schadstoffhaltiger",
data: Abfall_schadstoff,
backgroundColor: 'rgba(0, 0, 255, 0.2)'
};
var lineChart = new Chart(CHART, {
type: 'line',
data: {
labels: ['Jahr', 'Mahr', 'Kadr'],
datasets: [dts1]
},
options: {
responsive: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
stepSize: 1
}
}]
}
}
});
function myFunction() {
//lineChart.data.datasets[0].data = Abfall_schadstoff;
lineChart.data.datasets.push(dts2);
lineChart.update();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<button id="add" onclick="myFunction()">Add Dataset</button>
<canvas id="lineChart" height="190"></canvas>