I have two functions, one that gets data, and another that creates the chart. This works fine. Now I want to move the second function into a constructor, but I can't get the data to display, just an empty line chart. what am I missing?
Thanks
let data = getData() // returns arrays xs and cbrv
class BuildChart {
constructor() {
console.log(data) // <-- as expected
var ctx = document.getElementById('chart')
this.newChart = new Chart (ctx, {
type: 'line',
data: {
labels: data.xs, //
data: {
datasets: [{
labels: "cbrv",
data: data.cbrv
}],
}
}
})
}
}
function getData() {
return {
a: [{ x: 118, y: 92.82 }, {x: 115.8, y: 92.88 }, {x: 113.03, y: 93.62 } ],
b: [{ x: 218, y: 92.82 }, {x: 215.8, y: 92.88 }, {x: 213.03, y: 93.62 } ]
};
}
var data = getData();
class BuildChart {
constructor() {
var ctx = document.getElementById('myChart');
var myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [
{
label: 'Example',
showLine: true,
backgroundColor: 'red',
data: data.a
},
{
label: 'Example 2',
showLine: true,
backgroundColor: 'green',
data: data.b
}
]
}
});
}
}
new BuildChart();
canvas { max-width: 400px; }
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<canvas id="myChart"></canvas>
Related
considering the following example:
$(document).ready(function() {
var ctx = document.getElementById('mycanvas').getContext('2d');
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["CL", "ML", "Spl.L", "PD", "Other Permissions"],
datasets: [{
label: "My First dataset",
backgroundColor: ['#F0CB8C', '#EE97A1', '#A9D5D4', '#E8A3D7', '#CFA3FD'],
data: [7, 3, 3, 4, 8],
}]
},
options: {
legend: {
position: 'right'
}
}
});
})
example
is there a way to have the data on the right of the single label?
like here:
You can add custom labels as advised by #LeeLenalee's solution
and here is your workin code :
$(document).ready(function() {
var ctx = document.getElementById('mycanvas').getContext('2d');
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["CL", "ML", "Spl.L", "PD", "Other Permissions"],
datasets: [{
label: "My First dataset",
backgroundColor: ['#F0CB8C', '#EE97A1', '#A9D5D4', '#E8A3D7', '#CFA3FD'],
data: [7, 3, 3, 4, 8],
}]
},
options: {
legend: {
labels: {
generateLabels: (chart) => {
const datasets = chart.data.datasets;
return datasets[0].data.map((data, i) => ({
text: `${chart.data.labels[i]} ${data}`,
fillStyle: datasets[0].backgroundColor[i],
}))}
}
}
}
});
})
.chart-container {
width: 280px;
height: 280px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<div class="chart-container">
<canvas id="mycanvas"></canvas>
</div>
I am trying to make a line chart by using chart.js. But I facing a problem. I want to control the space between points, but the chart.js makes it equal.
Here is my code:
<canvas id="myChart"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.js" integrity="sha512-OD9Gn6cAUQezuljS6411uRFr84pkrCtw23Hl5TYzmGyD0YcunJIPSBDzrV8EeCiFxGWWvtJOfVo5pOgB++Jsag==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
var ctx = document.getElementById("myChart");
var points = [1,1,9,9.3];
var Dates = ["Dec 29th", "jan 10th", "Feb 21st", "Feb 25th"];
var myChart = new Chart(ctx, {
type: "line",
data: {
labels: Dates,
datasets: [
{
label: "My chart",
data: points,
backgroundColor: "black",
borderColor: "blue",
borderWidth: 3,
fill: false,
lineTension: 0.4,
}
]
},
options: {
legend: {display: false},
scales: {
yAxes:[{
ticks: {
min:1,
max: 9.9,
callback: function(value, index, values) {
return '$' + value;
}
}
}],
},
elements: {
point:{
radius: 0
}
}
}
});
</script>
Here is the result of my code:
But I want the big space in middle like this:
How can I make the big space between point 3 and point4, please?
Can you use time on the x axis?
Below is an example
// "+" before (new Date(2021,11,29)) return miliseconds from 1970 year
const dataA = [
{x:+new Date(2021,11,29), y:1}, // { x: 1640732400000, y: 1},
{x:+new Date(2022,0,10), y:1}, // { x: 1641769200000, y: 1},
{x:+new Date(2022,1,21), y:9}, // { x: 1645398000000, y: 9},
{x:+new Date(2022,1,25), y:9.3}, // { x: 1645743600000, y: 9.3}
];
const cfgChart = {
type: 'line',
data: {
datasets: [
{
backgroundColor: '#74adf7',
borderColor: '#74adf7',
data: dataA,
label: 'A',
lineTension: 0.4,
},
],
},
options: {
animation: false,
parsing: false,
interaction: {
mode: 'index',
axis: 'x',
intersect: false,
},
scales: {
x: {
type: 'time',
},
},
},
};
const chart = new Chart(document.querySelector('#chart').getContext('2d'), cfgChart);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.3.1/luxon.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-adapter-luxon/1.1.0/chartjs-adapter-luxon.min.js"></script>
<div>
<canvas id="chart"></canvas>
</div>
This is the code I'm using to display the chart
<canvas id="myChart"></canvas>
<script>
var data1 = [{
x: new Date("2020-01-01 18:00:00"),
y: 1
}, {
x: new Date("2020-01-02 18:00:00"),
y: 2
},{
x: new Date("2020-01-03 18:00:00"),
y: 3
}];
var ctx = document.getElementById('myChart');
console.log(data1);
var chart = new Chart(ctx, {
type: 'line',
data: data1,
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day'
},
distribution: 'linear',
}]
}
}
});
</script>
I've tried pasting a typical chart.js example from their website and the chart is displayed just fine. I have also tried using a string in the x-axis but that doesn't seem to work as well
Can't figure out why this is happening, any help would be greatly appreciated.
As palaѕн commented, you don't correctly retrieve the 2D-Context. This should look as follows.
var ctx = document.getElementById('myChart').getContext('2d');
Further the data object needs to be defined in a different way.
data: {
datasets: [{
data: data1
}]
},
Please have a look at your amended code below.
var data1 = [{
x: new Date("2020-01-01 18:00:00"),
y: 1
}, {
x: new Date("2020-01-02 18:00:00"),
y: 2
}, {
x: new Date("2020-01-03 18:00:00"),
y: 3
}];
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
data: data1
}]
},
data1,
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day'
},
distribution: 'linear',
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="myChart" height="120"></canvas>
Is it possible to get 2 separate types of chart (in this case bar and line) for the same dataset, but under one label?
As an example, this is my chart:
const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());
function getConfig() {
return {
type: 'bar',
data: {
labels: [ "Mar-20", "Apr-20" ],
datasets: [{
type: "line",
label: "en-US",
borderColor: "#8c856f",
data: [ 2, 3 ],
borderWidth: 2,
fill: false
}, {
type: "bar",
label: "en-US",
backgroundColor: "#beb391",
data: [ 2, 3 ]
}, {
type: "line",
label: "sv-SE",
borderColor: "#b3cbaa",
data: [ 1, 2 ],
borderWidth: 2,
fill: false
}, {
type: "bar",
label: "sv-SE",
backgroundColor: "#683e3a",
data: [ 1, 2 ]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
min : 0
}
}]
}
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart-container"></canvas>
As you can see, I have 4 datasets: 2 for each language (en & se). It all works perfectly fine except the legend labels are generated for each dataset (2 x "en-US", 2 x "sv-SE"), while I would like to show only the unique labels, essentially using the values from the main "labels" property, instead of the one inside each dataset.
Is it possible, and how can I do it?
You can filter out the labels for the line series via:
options: {
legend: {
labels: {
filter: function(item, chart) {
return chart.datasets[item.datasetIndex].type === 'bar';
}
},
onClick: function(e, legendItem) {
let chart = this.chart;
let index = legendItem.datasetIndex;
let visible = !chart.getDatasetMeta(index).hidden;
chart.data.datasets.forEach((dataset, i) => {
if (dataset.label === legendItem.text) {
chart.getDatasetMeta(i).hidden = visible;
}
});
chart.update();
}
}
}
This has been adapted from: Is it possible in chartjs to hide certain dataset legends?
For toggling the similar datasets, I followed this example.
Demo
const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());
function getConfig() {
return {
type: 'bar',
data: {
labels: ["Mar-20", "Apr-20"],
datasets: [{
type: "line",
label: "en-US",
borderColor: "#8c856f",
data: [2, 3],
borderWidth: 2,
fill: false
}, {
type: "bar",
label: "en-US",
backgroundColor: "#beb391",
data: [2, 3]
}, {
type: "line",
label: "sv-SE",
borderColor: "#b3cbaa",
data: [1, 2],
borderWidth: 2,
fill: false
}, {
type: "bar",
label: "sv-SE",
backgroundColor: "#683e3a",
data: [1, 2]
}]
},
options: {
legend: {
labels: {
filter: function(item, chart) {
return chart.datasets[item.datasetIndex].type === 'bar';
}
},
// Override hide/show for multiple series with same label.
onClick: function(e, legendItem) {
let chart = this.chart;
let index = legendItem.datasetIndex;
let visible = !chart.getDatasetMeta(index).hidden;
chart.data.datasets.forEach((dataset, i) => {
if (dataset.label === legendItem.text) {
chart.getDatasetMeta(i).hidden = visible;
}
});
chart.update();
}
},
scales: {
yAxes: [{
ticks: {
min: 0
}
}]
}
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
<canvas id="chart-container"></canvas>
Alternatively, you could create a plugin... This makes it so that you can configure each individual series.
var hideLegendItemsPlugin = {
beforeInit: function(chartInstance) {
if (chartInstance.options.hideLegendItemsPlugin) {
Object.assign(chartInstance.options.legend, {
labels : {
filter : (item, chart) => {
return chart.datasets[item.datasetIndex].hideLegendItem !== true;
}
},
onClick: function(e, legendItem) {
let chart = this.chart;
let index = legendItem.datasetIndex;
let visible = !chart.getDatasetMeta(index).hidden;
chart.data.datasets.forEach((dataset, i) => {
if (dataset.label === legendItem.text) {
chart.getDatasetMeta(i).hidden = visible;
}
});
chart.update();
}
});
}
}
};
Chart.pluginService.register(hideLegendItemsPlugin);
const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());
function getConfig() {
return {
type: 'bar',
data: {
labels: ["Mar-20", "Apr-20"],
datasets: [{
type: "line",
label: "en-US",
borderColor: "#8c856f",
data: [2, 3],
borderWidth: 2,
fill: false,
hideLegendItem: true // Hide it!
}, {
type: "bar",
label: "en-US",
backgroundColor: "#beb391",
data: [2, 3]
}, {
type: "line",
label: "sv-SE",
borderColor: "#b3cbaa",
data: [1, 2],
borderWidth: 2,
fill: false,
hideLegendItem: true // Hide it!
}, {
type: "bar",
label: "sv-SE",
backgroundColor: "#683e3a",
data: [1, 2]
}]
},
options: {
hideLegendItemsPlugin : true, // Enable the plugin
scales: {
yAxes: [{
ticks: {
min: 0
}
}]
}
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart-container"></canvas>
If you want to have the chart figure-out label uniqueness, you can build a set of series names behind the scenes.
I also added an option to specify priority of series type i.e. bar, line, etc... If you do not specify a priority, the last appearance of the label will take priority. This works in your example, because the bar series are after the line series. Obviously this can be tweaked a bit.
var hideLegendItemsPlugin = {
beforeInit: function(chartInstance) {
let pluginOptions = chartInstance.options.hideLegendItemsPlugin;
if (pluginOptions) {
if (pluginOptions.priority) {
const labelMap = chartInstance.data.datasets.reduce((ret, dataset) => {
return Object.assign(ret, {
[dataset.label] : (ret[dataset.label] || []).concat(dataset.type)
});
}, {});
chartInstance.options.legend.labels.filter = (item, chart) => {
let dataset = chart.datasets[item.datasetIndex];
if (dataset.type !== pluginOptions.priority) {
if (labelMap[dataset.label].includes(pluginOptions.priority)) {
return false;
}
}
return true;
};
} else {
// Default prioritization is the last index (appearance) of that label.
const labelMap = chartInstance.data.datasets.reduce((ret, dataset, index) => {
return Object.assign(ret, { [dataset.label] : index });
}, {});
chartInstance.options.legend.labels.filter = (item, chart) => {
let dataset = chart.datasets[item.datasetIndex];
return item.datasetIndex === labelMap[dataset.label];
};
}
chartInstance.options.legend.onClick = function(e, legendItem) {
let chart = this.chart;
let index = legendItem.datasetIndex;
let visible = !chart.getDatasetMeta(index).hidden;
chart.data.datasets.forEach((dataset, i) => {
if (dataset.label === legendItem.text) {
chart.getDatasetMeta(i).hidden = visible;
}
});
chart.update();
};
}
}
};
Chart.pluginService.register(hideLegendItemsPlugin);
const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());
function getConfig() {
return {
type: 'bar',
data: {
labels: ["Mar-20", "Apr-20"],
datasets: [{
type: "line",
label: "en-US",
borderColor: "#8c856f",
data: [2, 3],
borderWidth: 2,
fill: false
}, {
type: "bar",
label: "en-US",
backgroundColor: "#beb391",
data: [2, 3]
}, {
type: "line",
label: "sv-SE",
borderColor: "#b3cbaa",
data: [1, 2],
borderWidth: 2,
fill: false,
hideLegendItem: true
}, {
type: "bar",
label: "sv-SE",
backgroundColor: "#683e3a",
data: [1, 2]
}]
},
options: {
// This could also be simply `true` instead of an object.
hideLegendItemsPlugin : {
priority : 'bar'
},
scales: {
yAxes: [{
ticks: {
min: 0
}
}]
}
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart-container"></canvas>
I'm trying to set my own labels on the xAxis however I'm not sure how to do it using the example code I found.
I want it to look like this essentially: https://www.chartjs.org/samples/latest/scales/time/line.html
var result = [{ x: "00:01:53", y: "22" }, { x: "00:02:13", y: "45" }, { x: "00:02:43", y: "46" }, { x: "00:02:51", y: "51" }];
var result2 = [{ x: "00:01:52", y: "20" }, { x: "00:02:11", y: "42" }, { x: "00:02:41", y: "43" }, { x: "00:02:38", y: "50" }];
var labels = result.map(e => moment(e.x, 'h:mm:ss'));
var data = result.map(e => +e.y);
var data2 = result2.map(e => +e.y);
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'g-force',
data: data,
borderColor: "#3e95cd",
borderWidth: 1
},
{
label: 'g-force',
data: data2,
borderColor: "#8e5ea2",
borderWidth: 1
}
],
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'second',
displayFormats: {
second: 'h:mm:ss'
}
}
}]
},
}
});
This seems to work. This code starts from today and adds in the next 10 days. You'll have to change date to whenever you want your start date to be as well as how many dates you need.
let labels = [];
var date = new Date();
var options = {
month: "long",
day: "numeric"
};
for (i = 0; i < 10; i++) {
date.setDate(date.getDate() + i);
labels.push(date.toLocaleDateString("en-US", options));
}
var ctx = document.getElementById("myChart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
...