How to adjust spaces between points in chart js? - javascript

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>

Related

Chart,js stepSize working for right hand Y axis but not left hand Y axis

I have a chart with two Y axes, one on the left and one on the right. Both have a set min, max, and stepSize so that they have exactly 11 tick marks. The right hand Y axis seems to honor everything as expected but the left hand axis wont honor the stepSize.
The left hand Y axis goes from 3800 to 4140, which means if I want exactly 11 tick marks I should step by 34 and I have that set but it actually starts at 3800, ticks once by 8, then continues on ticking by 34 until it reaches 4114, and finally ticks for 26 to reach 4140. How can I stop this?
<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<body>
<div>
<table style="border-collapse: collapse; width: 1050px; padding-top: 10px; height: 1050px" border="0">
<canvas id="myChart2" style="width:100%;max-width:700px"></canvas>
<script>
var dates = ['07/29/2022', '08/01/2022', '08/02/2022', '08/03/2022', '08/04/2022', '08/05/2022', '08/06/2022', '08/07/2022', '08/08/2022', '08/09/2022', '08/10/2022', '08/11/2022'];
var portfolio_values = [3869.73, 3802.77, 3811.14, 3813.0, 3818.58, 3954.36, 3954.36, 3954.36, 3993.42, 3983.19, 4131.99, 4086.42];
var sp500_values = [378.79, 377.65, 375.21, 381.07, 380.77, 379.98, 379.98, 379.98, 379.64, 378.14, 386.06, 386.43];
new Chart("myChart2", {
type: "line",
data: {
labels: dates,
datasets: [{
fill: false,
lineTension: 0,
backgroundColor: "rgba(0,0,255,1.0)",
borderColor: "rgba(0,0,255,0.1)",
yAxisID: "A",
label: "Twitter",
data: portfolio_values
},
{
fill: false,
lineTension: 0,
backgroundColor: "rgba(255,0,0,1.0)",
borderColor: "rgba(255,0,0,0.1)",
yAxisID: "B",
label: "S&P500",
data: sp500_values
}
]
},
options: {
title: {
display: true,
text: "Twitter vs S&P500"
},
legend: {
display: true
},
scales: {
yAxes: [{
id: "A",
type: "linear",
position: "left",
ticks: {
min: 3800,
max: 4140,
stepSize: 34.0
}
},
{
id: "B",
type: "linear",
position: "right",
ticks: {
min: 370,
max: 390,
stepSize: 2.0
}
}
]
}
}
});
</script>
</table>
</div>
</body>
</html>
You could try to force to use your ticks implementing axis callback:
afterBuildTicks(axis, ticks) {
axis.ticks = [];
for (let i = axis.options.ticks.min; i<=axis.options.ticks.max; i+=axis.options.ticks.stepSize) {
axis.ticks.push(i);
}
}
var dates = ['07/29/2022', '08/01/2022', '08/02/2022', '08/03/2022', '08/04/2022', '08/05/2022', '08/06/2022', '08/07/2022', '08/08/2022', '08/09/2022', '08/10/2022', '08/11/2022'];
var portfolio_values = [3869.73, 3802.77, 3811.14, 3813.0, 3818.58, 3954.36, 3954.36, 3954.36, 3993.42, 3983.19, 4131.99, 4086.42];
var sp500_values = [378.79, 377.65, 375.21, 381.07, 380.77, 379.98, 379.98, 379.98, 379.64, 378.14, 386.06, 386.43];
const ctx = document.getElementById("myChart");
const myChart = new Chart(ctx, {
type: "line",
data: {
labels: dates,
datasets: [{
fill: false,
lineTension: 0,
backgroundColor: "rgba(0,0,255,1.0)",
borderColor: "rgba(0,0,255,0.1)",
yAxisID: "A",
label: "Twitter",
data: portfolio_values
},
{
fill: false,
lineTension: 0,
backgroundColor: "rgba(255,0,0,1.0)",
borderColor: "rgba(255,0,0,0.1)",
yAxisID: "B",
label: "S&P500",
data: sp500_values
}
]
},
options: {
title: {
display: true,
text: "Twitter vs S&P500"
},
legend: {
display: true
},
scales: {
yAxes: [{
id: "A",
type: "linear",
position: "left",
ticks: {
min: 3800,
max: 4140,
stepSize: 34
},
afterBuildTicks(axis, ticks) {
axis.ticks = [];
for (let i = axis.options.ticks.min; i<=axis.options.ticks.max; i+=axis.options.ticks.stepSize) {
axis.ticks.push(i);
}
}
},
{
id: "B",
type: "linear",
position: "right",
ticks: {
min: 370,
max: 390,
stepSize: 2,
}
}
]
}
}
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.4/dist/Chart.min.js"></script>
<html>
<body>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"/>
</div>
</body>
</html>

Chart.js sum y values depending on time unit

New to Chart.js, I was wondering if there is a built in method to sum y values depending on time unit.
Asking here after a lot of search in the docs.
For now, the bar for March shows 20 and the bar for June shows 10.
I want to have 25 for March and 15 for June, so to sum y for the same month.
const ctx = document.getElementById("tests-chart")
const testsChart = new Chart(ctx, {
type: "bar",
data: {
datasets: [
{
label: 'Dataset 1',
data: [
{ x: "24/03/2022", y: 20 },
{ x: "25/03/2022", y: 5 },
{ x: "24/06/2022", y: 10 },
{ x: "25/06/2022", y: 5 },
],
backgroundColor: 'rgb(255, 99, 132)',
},
],
},
options: {
scales: {
x: {
type: "time",
time: {
parser: "dd/MM/yyyy",
unit: "month",
// Luxon format string
tooltipFormat: "MM",
round: 'month'
},
},
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon#2.3.1/build/global/luxon.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon#1.1.0/dist/chartjs-adapter-luxon.min.js"></script>
<div>
<canvas id="tests-chart"></canvas>
</div>
You can manipulate your dataset as mentioned below and achieve your expected output.
const ctx = document.getElementById("tests-chart");
const data =[
{ x: "24/03/2022", y: 20 },
{ x: "25/03/2022", y: 5 },
{ x: "24/06/2022", y: 10 },
{ x: "25/06/2022", y: 5 }
];
let updatedData =[];
let tempDateCollection =[];
data.map((yData , index)=> {
const formatedDate = moment(yData.x, "DD/MM/YYYY").format('MMM/YYYY');
if(tempDateCollection.includes(formatedDate)){
const index = tempDateCollection.indexOf(formatedDate);
const element = updatedData[index];
updatedData[index] = {...element, y: element.y + yData.y}
} else{
tempDateCollection.push(formatedDate);
updatedData.push(yData);
}
})
const testsChart = new Chart(ctx, {
type: "bar",
data: {
datasets: [
{
label: 'Dataset 1',
data:updatedData,
backgroundColor: 'rgb(255, 99, 132)',
},
],
},
options: {
scales: {
x: {
type: "time",
time: {
parser: "dd/MM/yyyy",
unit: "month",
// Luxon format string
tooltipFormat: "MM",
round: 'month'
},
},
},
},
})
<script type = "text/JavaScript" src = " https://MomentJS.com/downloads/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon#2.3.1/build/global/luxon.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon#1.1.0/dist/chartjs-adapter-luxon.min.js"></script>
<div>
<canvas id="tests-chart"></canvas>
</div>

Charts.js display two combined line charts for last 7 days

I have 2 set of datasets I want to display in single line chart for last 7 days, and if possible only show single Y axis with max value from all data sets. I try to use time as xAxes but it is not showing up.
here is my code https://jsfiddle.net/e6trkxL0/
You have to place the labels for datapoints.
let start = new Date(),
end = new Date();
start.setDate(start.getDate() - 7); // set to 'now' minus 7 days.
start.setHours(0, 0, 0, 0); // set to midnight.
let chart = new Chart(document.getElementById("lastSevenDaysOverview"), {
type: "line",
data: {
labels: [],
datasets: [{
label: 'Dataset 1',
data: [1, 4, 66, 7, 12, 3, 8],
borderColor: '#ff3366',
backgroundColor: '#ff3366',
},
{
label: 'Dataset 2',
data: [31, 14, 6, 71, 1, 35, 9],
borderColor: '#880000',
backgroundColor: '#880000',
}
]
},
options: {
interaction: {
mode: 'index',
intersect: true,
},
stacked: false,
responsive: true,
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
},
xAxes: [{
type: "time",
// this is not doing much
// time: {
// min: start,
// max: end,
// unit: "day"
//}
}]
}
}
});
chart.render();
for (let i = 0; i < 7; i++) {
var labelDate = start;
labelDate.setDate(start.getDate() + 1);
chart.data.labels.push(labelDate.toLocaleString())
}
chart.update();
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<canvas id="lastSevenDaysOverview"></canvas>
2 things, for a time axis in chart.js you need according to the documentation a time adapter. Also you defined you x axis scales as a array which is incorrect. You need to define all scales as an object where the key of the object is the scale ID, you can read more about it in the migration guide
For points to be mapped in the chart you also need to provide a x place which in this case needs to be the date for which the datapoint is valid.
To just show a single axis with the highest values you can let both datasets be mapped to the same y axis:
let start = new Date(),
end = new Date();
start.setDate(start.getDate() - 7); // set to 'now' minus 7 days.
start.setHours(0, 0, 0, 0); // set to midnight.
new Chart(document.getElementById("lastSevenDaysOverview"), {
type: "line",
data: {
datasets: [{
label: 'Dataset 1',
data: [{
x: new Date('10-16-2021'),
y: 1
}, {
x: new Date('10-18-2021'),
y: 4
}, {
x: new Date('10-19-2021'),
y: 66
}],
borderColor: '#ff3366',
backgroundColor: '#ff3366',
},
{
label: 'Dataset 2',
data: [{
x: new Date('10-14-2021'),
y: 31
}, {
x: new Date('10-18-2021'),
y: 14
}, {
x: new Date('10-19-2021'),
y: 6
}],
borderColor: '#880000',
backgroundColor: '#880000'
}
]
},
options: {
interaction: {
mode: 'index',
intersect: true,
},
responsive: true,
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
},
x: {
type: "time",
min: start,
max: end,
time: {
unit: "day"
}
}
},
}
});
<canvas id="lastSevenDaysOverview"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>

Chartjs, Bubble Chart, positioning problem with duplicate value in data labels

With a duplicate value in the data labels - Is there a way to draw the bubble on the first or second duplicate value in the bubble chart?
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var ctx = document.getElementById("myChart");
var options = {responsive: true,
maintainAspectRatio: false,
};
var mixedChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["1", "2", "1", "4"], //Same Value on First and Third Position
datasets: [
//Lines
{
label: "First_Line",
type: "line",
borderColor: "#8e5ea2",
data: [5,10,7,12],
fill: false
}, {
label: "Second_Line",
type: "line",
borderColor: "#3e95cd",
data: [1,4,15,6],
fill: false
},
//Bubbles
{
label: "Bubble_One",
type: "bubble",
backgroundColor: "#8e5ea2",
data: [{ x: "2", y: 10, r: 15}],
},
{
label: "Bubble_Two",
type: "bubble",
backgroundColor: "#3e95cd",
backgroundColorHover: "#3e95cd",
data: [{x: ???, y: 6, r: 15}] //First "1" or Second "1" possible?
}
]
},
options: options
});
</script>
Something like "1"[0] unfortunately does not work.
You can not do it directly afaik but you can put an extra part in the label and filter it out of there with the callbacks for the tooltip and the axis:
<canvas id="myChart"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
var ctx = document.getElementById("myChart");
var options = {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
offset: false,
ticks: {
callback: function(val) {
return this.getLabelForValue(val).split('-')[0]
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: (ttItem) => {
if (ttItem.dataset.type === "bubble") {
return `${ttItem.label}: (${ttItem.raw.x.split('-')[0]},${ttItem.raw.y})`
} else if (ttItem.dataset.type === "line") {
return `${ttItem.dataset.label}: ${ttItem.parsed.y}`
}
},
title: (ttItem) => (ttItem[0].label.split('-')[0])
}
}
}
};
var mixedChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["1-1", "2", "1-2", "4"], //Same Value on First and Third Position
datasets: [
//Lines
{
label: "First_Line",
type: "line",
borderColor: "#8e5ea2",
data: [5, 10, 7, 12],
fill: false
}, {
label: "Second_Line",
type: "line",
borderColor: "#3e95cd",
data: [1, 4, 15, 6],
fill: false
},
//Bubbles
{
label: "Bubble_One",
type: "bubble",
backgroundColor: "#8e5ea2",
data: [{
x: "2",
y: 10,
r: 15
}],
},
{
label: "Bubble_Two",
type: "bubble",
backgroundColor: "#3e95cd",
backgroundColorHover: "#3e95cd",
data: [{
x: "1-2",
y: 6,
r: 15
}] //First "1" or Second "1" possible?
}
]
},
options: options
});
</script>

How to show xaxis lable o only data point and hide all others?

I have a chartjs line chart requirement where the client is asking to show labels on x axis only if it has a data point. please find his mockup below.
the x-axis is time and here is what I am getting.
how can I achieve this?
here is my config.
options={{
scales: {
xAxes: [
{
distribution: 'linear',
type: "time",
time: {
min: range_min.toDateString(),
max: range_max.toDateString(),
unit: "day",
stepSize: "1",
},
id: 'xAxis',
ticks: {
autoSkip: true,
callback: function (value, index, values) {
return formatDate(new Date(value))
},
}
},
],
},
pan: {
enabled: true,
mode: "x",
speed: 1,
threshold: 1,
},
zoom: {
enabled: true,
drag: true,
sensitivity: 0.5,
mode: "x",
},
annotation: {
annotations: [{
type: 'line',
mode: 'vertical',
scaleID: 'xAxis',
value: 1582229218219,
endValue: 1582229218219,
borderColor: 'rgb(75, 0, 0)',
borderWidth: 4
}]
},
onClick: (event, item) => {
console.log(item)
}
}}
yes this is possible, you can achieve this by using the tick callback like so:
const data = [{
x: 'Red',
y: 10
}, {
x: 'Yellow',
y: 5
}, {
x: 'Orange',
y: 3
}]
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data,
borderWidth: 1,
backgroundColor: 'red',
borderColor: 'red',
fill: false
}]
},
options: {
scales: {
xAxes: [{
ticks: {
callback: (val, y, z, t) => (
data.map(el => el.x).indexOf(val) >= 0 ? val : null
)
}
}]
}
}
}
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/2.9.4/Chart.js" integrity="sha512-hZf9Qhp3rlDJBvAKvmiG+goaaKRZA6LKUO35oK6EsM0/kjPK32Yw7URqrq3Q+Nvbbt8Usss+IekL7CRn83dYmw==" crossorigin="anonymous"></script>
</body>

Categories

Resources